diff --git a/QuestHelper/director_find.lua b/QuestHelper/director_find.lua index 3ed6576..6e9b08c 100644 --- a/QuestHelper/director_find.lua +++ b/QuestHelper/director_find.lua @@ -17,14 +17,14 @@ local function getitall(name) segments[dbi] = true end end - + local segwork = {} for k in pairs(segments) do table.insert(segwork, {k, 1, k[1]}) end - + local found = {} - + while true do local lowest = segwork[1][3] local highest = segwork[1][3] @@ -41,7 +41,7 @@ local function getitall(name) highest = v end end - + if lowest == highest then table.insert(found, lowest) segwork[1][2] = segwork[1][2] + 1 @@ -54,10 +54,10 @@ local function getitall(name) segwork[lid][3] = segwork[lid][3] + segwork[lid][1][segwork[lid][2]] end end - + if not segwork[lid][1][segwork[lid][2]] then break end end - + return found end @@ -73,7 +73,7 @@ local function generate_objective(dbi) QuestHelper: Assert(QuestHelper_ParentLookup[v.p], v.p) table.insert(clooster, {loc = {x = v.x, y = v.y, c = QuestHelper_ParentLookup[v.p], p = v.p}, cluster = clooster, tracker_hidden = true, why = why, map_desc = {QuestHelper:HighlightText(dbi.name)}, tracker_desc = dbi.name, map_suppress_ignore = true, map_custom_menu = function (menu) QuestHelper:CreateMenuItem(menu, QHText("FIND_REMOVE")):SetFunction(function () QH_Route_ClusterRemove(clooster) end) end}) end - + QH_Route_ClusterAdd(clooster) custom_find[dbi.name] = clooster else @@ -84,29 +84,30 @@ end local msfires = {desc = QHText("FIND_CUSTOM_LOCATION"), tracker_desc = QHText("FIND_CUSTOM_LOCATION")} -local function QH_FindCoord(locx, locy, locz, label) - if type(locz) ~= "number" then -- If it is a number, we are probably doing an elder right now. - label = locz .. " (" .. locx .. ", " .. locy .. ")" +local function QH_FindCoord(locx, locy, locm, locf, label) + -- Note: this part will not work until something is done about QuestHelper_NameLookup + if type(locm) ~= "number" then -- If it is a number, we are probably doing an elder right now. + label = locm .. " (" .. locx .. ", " .. locy .. ")" for z, nam in pairs(QuestHelper_NameLookup) do - if nam:lower():find(locz:lower()) then - locz = z + if nam:lower():find(locm:lower()) then + locm = z break end end end - - if type(locz) == "number" then - if not custom_find[label] then - local ec, ez = unpack(QuestHelper_ZoneLookup[locz]) - local c, x, y = QuestHelper.Astrolabe:GetAbsoluteContinentPosition(ec, ez, locx / 100, locy / 100) - local node = {loc = {x = x, y = y, p = locz, c = QuestHelper_ParentLookup[locz]}, why = {desc = label, tracker_desc = label}, map_desc = {label}, tracker_desc = label, tracker_hidden = true} + + if type(locm) == "number" then + if not custom_find[label] then + local em, ef = locm, locf + local x, y = locx / 100, locy / 100 + local node = {loc = {x = x, y = y, m = em, f = ef}, why = {desc = label, tracker_desc = label}, map_desc = {label}, tracker_desc = label, tracker_hidden = true} local cluster = {node} node.cluster = cluster - custom_find[label] = cluster + custom_find[label] = cluster node.map_suppress_ignore = true node.map_custom_menu = function (menu) QuestHelper:CreateMenuItem(menu, QHText("FIND_REMOVE")):SetFunction(function () QH_Route_ClusterRemove(cluster); custom_find[cluster.tracker_desc] = nil end) end - + QH_Route_ClusterAdd(cluster) else QH_Route_ClusterRemove(custom_find[label]) @@ -118,18 +119,18 @@ end local function QH_FindLoc(locd) -- I just know some guy's gonna get pissed off because he was trying to find "loc crocolisk" or something, but screw him local locx, locy, locz - + locx, locy = locd:match("^(%d+) (%d+)$") if locx and locy then locx, locy = tonumber(locx), tonumber(locy) locz = QuestHelper_NameLookup[QuestHelper_IndexLookup[QuestHelper.routing_c][QuestHelper.routing_z]] end - + if not locx then locz, locx, locy = locd:match("^(.+) (%d+) (%d+)$") locx, locy = tonumber(locx), tonumber(locy) end - + if locz then QH_FindCoord(locx, locy, locz, QHText("FIND_CUSTOM_LOCATION")) end @@ -144,7 +145,7 @@ local elders = { ["Horde"] = { -- Achievement 914 ["Darkhorn"] = {321, 52, 60, 8677, 1991}, --"Orgrimmar 52 60", ["Wheathoof"] = {362, 73.0, 23.3, 8678, 1993}, --"Thunder Bluff 73.0 23.3", - ["Darkcore"] = {382, 67, 38, 8648, 1992}, --"Undercity 67 38" + ["Darkcore"] = {382, 67, 38, 8648, 1992}, --"Undercity 67 38" -- Might have a floor. }, ["Kalimdor"] = { -- Achievement 911 ["Bladeleaf"] = { 41, 56.8, 53.1, 8715, 1951}, --"Teldrassil 56.8 53.1", @@ -219,6 +220,8 @@ local elders = { ["Firebeard"] = {700, 51, 71, 29737, 18161}, -- Dunward Town Square, Dunward Ruins, Twilight Highlands ["Darkfeather"] = {700, 52, 33, 29736, 18162} -- Thundermar Ruins, Twilight Highlands }, + ["Pandaria"] = { -- Unknown atm. + }, --[===[ Placeholder for Elders of the Dungeons. If enabled prior to 2013, stored coordinates should be the map ID of the zone where the instance is located and the coordinates of the entrance. With any luck, by 2013 dungeons will be mapable. Coordinates listed in comment after each elder need to have floor numbers determined, where necessary, ASAP. ["Dungeons"] = { -- Achievement 910 ["Wildmane"] = {,,,8676, 1910}, -- Zul'Farrak 34.52 39.35 @@ -244,9 +247,9 @@ local function UpdateElders() local elder, elderinfo local qid = GetQuestID() for elder, elderinfo in pairs(trackedElders) do - local z, x, y, id = unpack(elderinfo) + local m, x, y, id = unpack(elderinfo) if id == qid then - QH_FindCoord(x, y, z, elder) + QH_FindCoord(x, y, m, 0, elder) trackedElders[elder] = nil return end @@ -259,7 +262,7 @@ local function QH_FindElders(elder_or_achievement, all_elders, forAchievement) if elder_or_achievement == "CLEAR" then for elder, elderinfo in pairs(trackedElders) do local z, x, y = unpack(elderinfo) - QH_FindCoord(x, y, z, elder) + QH_FindCoord(x, y, m, 0, elder) end trackedElders = {} @@ -276,41 +279,41 @@ local function QH_FindElders(elder_or_achievement, all_elders, forAchievement) end for elder, elder_info in pairs(eldrs) do - local locz, locx, locy, qid, aid = unpack(elder_info) + local locm, locx, locy, qid, aid = unpack(elder_info) local okToAdd = true if forAchievement then - if aid then - local _, _, completed = GetAchievementCriteriaInfo(aid) - if completed then okToAdd = false end - end + if aid then + local _, _, completed = GetAchievementCriteriaInfo(aid) + if completed then okToAdd = false end + end elseif qid and QHQuestsCompleted and QHQuestsCompleted[qid] then okToAdd = false end if okToAdd then - if not all_elders then + if not all_elders then if achievement_match then -- just add it - QH_FindCoord(locx, locy, locz, elder) - if trackedElders[elder] then trackedElders[elder] = nil - else - trackedElders[elder] = elder_info - elderCount = elderCount + 1 - end - elseif elder_or_achievement == string.upper(elder) then -- We have input and it's not an achievement, so it must be an elder. + QH_FindCoord(locx, locy, locm, 0, elder) + if trackedElders[elder] then trackedElders[elder] = nil + else + trackedElders[elder] = elder_info + elderCount = elderCount + 1 + end + elseif elder_or_achievement == string.upper(elder) then -- We have input and it's not an achievement, so it must be an elder. elder_match = true - QH_FindCoord(locx, locy, locz, elder) - if trackedElders[elder] then trackedElders[elder] = nil - else - trackedElders[elder] = elder_info - elderCount = elderCount + 1 - end + QH_FindCoord(locx, locy, locm, 0, elder) + if trackedElders[elder] then trackedElders[elder] = nil + else + trackedElders[elder] = elder_info + elderCount = elderCount + 1 + end break -- We've found him or her. end -- No need for else here. We alread know we don't need everything so we either have an achievement or we have an elder. else -- We came in without an input, therefore we add all. - QH_FindCoord(locx, locy, locz, elder) + QH_FindCoord(locx, locy, locm, 0, elder) if trackedElders[elder] then trackedElders[elder] = nil - else + else trackedElders[elder] = elder_info elderCount = elderCount + 1 end @@ -327,10 +330,10 @@ end function QH_FindName(name) local locd = name:match("^loc (.+)") local forAchievement = false, elder_loc, temp - + if not locd then if name:find("^elders?") then - if name:find("^elders? achievement") then + if name:find("^elders? achievement") then forAchievement = true elder_loc = name:match("elders? achievement (.+)") else @@ -350,52 +353,52 @@ function QH_FindName(name) QuestHelper:TextOut(QHText("FIND_NOT_READY")) return end - + if #name < 2 then QuestHelper:TextOut(QHText("FIND_USAGE")) return end - + local found = getitall(name) - + local mennix = QuestHelper:CreateMenu() QuestHelper:CreateMenuTitle(mennix, QHText("RESULTS_TITLE")) - + local made_item = false - + local found_db = {} local has_name = {} local needs_postfix = {} - + for _, v in ipairs(found) do local dbi = DB_GetItem("monster", v) --[[ assert(dbi) ]] - + if dbi.loc then table.insert(found_db, dbi) - + if has_name[dbi.name] then needs_postfix[dbi.name] = true end has_name[dbi.name] = true end end - + table.sort(found_db, function (a, b) return a.name < b.name end) - + for _, v in ipairs(found_db) do made_item = true - + local name = v.name - + if needs_postfix[name] then name = name .. " (" .. QuestHelper_NameLookup[v.loc[1].p] .. ")" end - + local opt = QuestHelper:CreateMenuItem(mennix, name) opt:SetFunction(generate_objective, v) end - + if not made_item then QuestHelper:CreateMenuItem(mennix, QHText("NO_RESULTS")) end - + mennix:ShowAtCursor() end end @@ -407,5 +410,5 @@ end QH_API.ARCHY_REMOVE = function (displayText) if not custom_find[displayText] then return end QH_Route_ClusterRemove(custom_find[displayText]) - custom_find[displayText] = nil + custom_find[displayText] = nil end diff --git a/QuestHelper/dodads.lua b/QuestHelper/dodads.lua index 0ad4957..41e4b05 100644 --- a/QuestHelper/dodads.lua +++ b/QuestHelper/dodads.lua @@ -8,24 +8,28 @@ local radius = ofs / 1.166666666666667; local Minimap = _G.Minimap -- These conversions are nasty, and this entire section needs a serious cleanup. +local function GetCurrentMapMF() + return GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() +end local function convertLocation(p) QuestHelper: Assert(p, "Wait. What? This is checked before calling this function.") - QuestHelper: Assert(p.c, "p.c is nil") - QuestHelper: Assert(p.x, "p.x is nil") - QuestHelper: Assert(p.y, "p.y is nil") - return QuestHelper.Astrolabe:FromAbsoluteContinentPosition(p.c, p.x, p.y) + QuestHelper: Assert(p.m, "No Map ID") + QuestHelper: Assert(p.f, "No Floor") + QuestHelper: Assert(p.x, "No X") + QuestHelper: Assert(p.y, "No Y") + return p.m, p.f, p.x, p.y --QuestHelper.Astrolabe:FromAbsoluteContinentPosition(p.c, p.x, p.y) end -local function convertLocationToScreen(p, c, z) - local pc, _, px, py = convertLocation(p) - local ox, oy = QuestHelper.Astrolabe:TranslateWorldMapPosition(pc, 0, px, py, c, z) +local function convertLocationToScreen(p, m, f) + local pm, _, px, py = convertLocation(p) + local ox, oy = QuestHelper.Astrolabe:TranslateWorldMapPosition(pm, 0, px, py, m, f) --QuestHelper:TextOut(string.format("%f/%f/%f to %f/%f/%f to %f/%f %f/%f", p.c, p.x, p.y, pc, px, py, c, z, ox, oy)) return ox, oy end -local function convertRawToScreen(tc, x, y, c, z) - local rc, _, rx, ry = QuestHelper.Astrolabe:FromAbsoluteContinentPosition(tc, x, y) - return QuestHelper.Astrolabe:TranslateWorldMapPosition(rc, 0, rx, ry, c, z) +local function convertRawToScreen(tm, x, y, m, f) + local rm, _, rx, ry = tm, x, y --QuestHelper.Astrolabe:FromAbsoluteContinentPosition(tc, x, y) + return QuestHelper.Astrolabe:TranslateWorldMapPosition(rm, 0, rx, ry, m, f) end local scrolf = CreateFrame("SCROLLFRAME", nil, WorldMapButton) @@ -46,47 +50,47 @@ local function ClampLine(x1, y1, x2, y2) local x_1 = y1+(1-x1)/x_div*y_div local y_0 = x1-y1/y_div*x_div local y_1 = x1+(1-y1)/y_div*x_div - + if y1 < 0 then x1 = y_0 y1 = 0 end - + if y2 < 0 then x2 = y_0 y2 = 0 end - + if y1 > 1 then x1 = y_1 y1 = 1 end - + if y2 > 1 then x2 = y_1 y2 = 1 end - + if x1 < 0 then y1 = x_0 x1 = 0 end - + if x2 < 0 then y2 = x_0 x2 = 0 end - + if x1 > 1 then y1 = x_1 x1 = 1 end - + if x2 > 1 then y2 = x_1 x2 = 1 end - + if x1 >= 0 and x2 >= 0 and y1 >= 0 and y2 >= 0 and x1 <= 1 and x2 <= 1 and y1 <= 1 and y2 <= 1 then return x1, y1, x2, y2 end @@ -121,14 +125,14 @@ function QuestHelper:CreateWorldMapWalker() if not self.Astrolabe or not QuestHelper then return end QuestHelper: Assert(self == QuestHelper) QuestHelper: Assert(self.Astrolabe) - + local walker = CreateFrame("Button", nil, QuestHelper.map_overlay) walker_loc = walker walker:SetWidth(0) walker:SetHeight(0) walker:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", 0, 0) walker:Show() - + walker.phase = 0.0 walker.dots = {} walker.points = {} @@ -136,37 +140,37 @@ function QuestHelper:CreateWorldMapWalker() walker.frame = self walker.map_dodads = {} walker.used_map_dodads = 0 - + function walker:OnUpdate(elapsed) if poi_changed then self:RouteChanged() end -- bzzzzt - + local out = 0 - + if QuestHelper_Pref.show_ants then local points = self.points - + self.phase = self.phase + elapsed * 0.66 while self.phase > 1 do self.phase = self.phase - 1 end - + local w, h = QuestHelper.map_overlay:GetWidth(), -QuestHelper.map_overlay:GetHeight() - - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - - local last_x, last_y = self.frame.Astrolabe:TranslateWorldMapPosition(self.frame.c, self.frame.z, self.frame.x, self.frame.y, c, z) + + local m, f = GetCurrentMapMF() + + local last_x, last_y = self.frame.Astrolabe:TranslateWorldMapPosition(self.frame.m, self.frame.f, self.frame.x, self.frame.y, m, f) local remainder = self.phase - + for i, pos in ipairs(points) do local new_x, new_y = unpack(pos) local x1, y1, x2, y2 = ClampLine(last_x, last_y, new_x, new_y) last_x, last_y = new_x, new_y - + if x1 then local len = math.sqrt((x1-x2)*(x1-x2)*16/9+(y1-y2)*(y1-y2)) - + if len > 0.0001 then local interval = .025/len local p = remainder*interval - + while p < 1 do out = out + 1 local dot = self.dots[out] @@ -175,70 +179,70 @@ function QuestHelper:CreateWorldMapWalker() dot:SetDrawLayer("BACKGROUND") self.dots[out] = dot end - + dot:ClearAllPoints() dot:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x1*w*(1-p)+x2*w*p, y1*h*(1-p)+y2*h*p) - + p = p + interval end - + remainder = (p-1)/interval end end end end - + while #self.dots > out do QuestHelper:ReleaseTexture(table.remove(self.dots)) end end - + function walker:RouteChanged(route) if route then self.route = route end -- we cache it so we can refer to it later when the world map changes if not self.route then return end - + local dbgstr = string.format("%s %s %s %s", tostring(self), tostring(self.frame), tostring(QuestHelper), tostring(QuestHelper and QuestHelper.Astrolabe)) QuestHelper: Assert(self.frame == QuestHelper, dbgstr) QuestHelper: Assert(QuestHelper.Astrolabe, dbgstr) - + if self.next_item then self.next_item:MarkAsNext(false) self.next_item = nil end - + if self.frame.Astrolabe.WorldMapVisible then local points = self.points local cur = self.frame.pos - + while #points > 0 do self.frame:ReleaseTable(table.remove(points)) end - - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - + + local m, f = GetCurrentMapMF() + for i, obj in ipairs(self.route) do --QuestHelper:TextOut(string.format("%s", tostring(obj))) - + --[[ local t = QuestHelper:CreateTable() t[1], t[2] = convertLocationToScreen(obj.loc, c, z) - + table.insert(list, t)]] - + -- We're ignoring travel time for now. --[[ travel_time = travel_time + 60 obj.travel_time = travel_time]] if i > 1 then -- skip the start location local t = self.frame:CreateTable() - t[1], t[2] = convertLocationToScreen(obj.loc, c, z) - + t[1], t[2] = convertLocationToScreen(obj.loc, m, f) + table.insert(points, t) - + --if lotsup then print(obj.ignore, obj.loc.x, obj.loc.y, obj.loc.c) end end --QuestHelper:TextOut(string.format("%s/%s/%s to %s/%s", tostring(obj.c), tostring(obj.x), tostring(obj.y), tostring(t[1]), tostring(t[2]))) end --lotsup = false - + local cur_dodad = 1 for i = 2, #self.route do -- 2 because we're skipping the player if not self.route[i].ignore or qh_hackery_show_all_map_nodes then @@ -248,7 +252,7 @@ function QuestHelper:CreateWorldMapWalker() else self.map_dodads[cur_dodad]:SetObjective(self.route[i], i == 2) end - + if cur_dodad == 1 then self.map_dodads[cur_dodad]:MarkAsNext(true) self.next_item = self.map_dodads[cur_dodad] @@ -262,11 +266,11 @@ function QuestHelper:CreateWorldMapWalker() end end self.used_map_dodads = cur_dodad - 1 - + while #poi > #poi_dodads do table.insert(poi_dodads, self.frame:CreateWorldMapMinidad()) end - + for i = 1, #poi do poi_dodads[i]:SetPosition(poi[i]) end @@ -275,11 +279,11 @@ function QuestHelper:CreateWorldMapWalker() end end end - + QH_Event("WORLD_MAP_UPDATE", function () walker:RouteChanged() end) - + QH_Hook(walker, "OnUpdate", walker.OnUpdate) - + return walker end @@ -287,26 +291,26 @@ end function QuestHelper:GetOverlapObjectives(obj) local w, h = self.map_overlay:GetWidth(), self.map_overlay:GetHeight() - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - + local m, f = GetCurrentMapMF() + local list = self.overlap_list - + if not list then list = {} self.overlap_list = list else while table.remove(list) do end end - + local cx, cy = GetCursorPosition() - + local es = QuestHelper.map_overlay:GetEffectiveScale() local ies = 1/es - + cx, cy = (cx-self.map_overlay:GetLeft()*es)*ies, (self.map_overlay:GetTop()*es-cy)*ies - + local s = 10*QuestHelper_Pref.scale - + for i, o in ipairs(walker_loc.route) do --QuestHelper: Assert(o, string.format("nil dodads pos issue, o %s", tostring(o))) --QuestHelper: Assert(o.pos, string.format("nil dodads pos issue, pos %s", QuestHelper:StringizeTable(o))) @@ -314,11 +318,11 @@ function QuestHelper:GetOverlapObjectives(obj) if o == obj then table.insert(list, o) else - local x, y = convertLocationToScreen(o.loc, c, z) - + local x, y = convertLocationToScreen(o.loc, m, f) + if x and y and x > 0 and y > 0 and x < 1 and y < 1 then x, y = x*w, y*h - + if cx >= x-s and cy >= y-s and cx <= x+s and cy <= y+s then table.insert(list, o) end @@ -326,24 +330,24 @@ function QuestHelper:GetOverlapObjectives(obj) end end end - + table.sort(list, function(a, b) return (a.distance or 0) < (b.distance or 0) end) - + return list end function QuestHelper:AppendObjectiveProgressToTooltip(o, tooltip, font, depth) if o.progress then local prog_sort_table = {} - + local theme = self:GetColourTheme() - + local indent = (" "):rep(depth or 0) - + for user, progress in pairs(o.progress) do table.insert(prog_sort_table, user) end - + table.sort(prog_sort_table, function(a, b) if o.progress[a][3] < o.progress[b][3] then return true @@ -352,39 +356,39 @@ function QuestHelper:AppendObjectiveProgressToTooltip(o, tooltip, font, depth) end return false end) - + for i, u in ipairs(prog_sort_table) do tooltip:AddDoubleLine(indent..QHFormat("PEER_PROGRESS", u), self:ProgressString(o.progress[u][1].."/"..o.progress[u][2], o.progress[u][3]), unpack(theme.tooltip)) - + if font then local last, name = tooltip:NumLines(), tooltip:GetName() local left, right = _G[name.."TextLeft"..last], _G[name.."TextRight"..last] - + left:SetFont(font, 13) right:SetFont(font, 13) end end - + while table.remove(prog_sort_table) do end end end function QuestHelper:AppendObjectiveToTooltip(o) local theme = self:GetColourTheme() - + QuestHelper: Assert(o.map_desc) for _, v in ipairs(o.map_desc) do self.tooltip:AddLine(v, unpack(theme.tooltip)) self.tooltip:GetPrevLines():SetFont(self.font.serif, 14) end - + if o.map_desc_chain then self:AppendObjectiveToTooltip(o.map_desc_chain) else self:AppendObjectiveProgressToTooltip(o, self.tooltip, QuestHelper.font.sans) - + if QuestHelper_Pref.travel_time then self.tooltip:AddDoubleLine(QHText("TRAVEL_ESTIMATE"), QHFormat("TRAVEL_ESTIMATE_VALUE", o.distance or 0), unpack(theme.tooltip)) self.tooltip:GetPrevLines():SetFont(self.font.sans, 11) @@ -398,7 +402,7 @@ globy = 0.5 function QH_Append_NextObjective(menu) local obj = QuestHelper.minimap_marker.obj if not obj then return end - + QuestHelper:AddObjectiveOptionsToMenu(obj, menu) end @@ -407,10 +411,10 @@ local function rightclick_menu(obj) local menu = QuestHelper:CreateMenu() local list = QuestHelper:GetOverlapObjectives(obj) local item - + if #list > 1 then QuestHelper:CreateMenuTitle(menu, "Objectives") - + for i, o in ipairs(list) do local submenu = QuestHelper:CreateMenu() item = QuestHelper:CreateMenuItem(menu, o.map_desc[1]) @@ -422,7 +426,7 @@ local function rightclick_menu(obj) QuestHelper:CreateMenuTitle(menu, obj.map_desc[1]) QuestHelper:AddObjectiveOptionsToMenu(obj, menu) end - + menu:ShowAtCursor() end end @@ -450,13 +454,13 @@ end function QuestHelper:CreateWorldMapDodad(objective, nxt) local icon = CreateFrame("Button", nil, QuestHelper.map_overlay) icon:SetFrameStrata("FULLSCREEN") - + function icon:SetTooltip(list) QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR") QuestHelper.tooltip:ClearLines() - + local first = true - + for i, o in ipairs(list) do if first then first = false @@ -464,36 +468,36 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper.tooltip:AddLine("|c80ff0000 . . . . . .|r") QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.sans, 8) end - + QuestHelper:AppendObjectiveToTooltip(o) end - + QuestHelper.tooltip:Show() end - + function icon:MarkAsNext(nxt) self.next = nxt - + QH_Hook(self, "OnUpdate", self.OnUpdate) end - + function icon:SetObjective(objective, nxt) self:SetHeight(20*QuestHelper_Pref.scale) self:SetWidth(20*QuestHelper_Pref.scale) - + if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end - + if self.bg then QuestHelper:ReleaseTexture(self.bg) self.bg = nil end - + if objective then self.objective = objective - + if nxt then self.bg = QuestHelper:CreateIconTexture(self, 13) elseif objective.map_highlight then @@ -501,14 +505,14 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) else self.bg = QuestHelper:CreateIconTexture(self, 16) end - + self.dot = QuestHelper:CreateIconTexture(self, objective.icon_id or 8) - + self.bg:SetDrawLayer("BACKGROUND") self.bg:SetAllPoints() self.dot:SetPoint("TOPLEFT", self, "TOPLEFT", 3*QuestHelper_Pref.scale, -3*QuestHelper_Pref.scale) self.dot:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3*QuestHelper_Pref.scale, 3*QuestHelper_Pref.scale) - + QuestHelper: Assert(objective, "Missing objective.") QuestHelper: Assert(objective.loc, "Missing Location.") local locarray = {convertLocation(objective.loc)} @@ -523,13 +527,13 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) self:OnUpdate(0) end end - + local triangle_r, triangle_g, triangle_b = 1.0, 0.3, 0 local triangle_opacity = 0.6 - + function icon:CreateTriangles(solid, tritarget, tristartat, linetarget, linestartat, parent) - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - + local m, f = GetCurrentMapMF() + local function makeline(ax, ay, bx, by) local tri = linetarget[linestartat] if not tri then @@ -537,33 +541,33 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) table.insert(linetarget, tri) end linestartat = linestartat + 1 - + tri:SetLine(ax, ay, bx, by) tri:SetVertexColor(0, 0, 0, 0) tri:Show() end - + for _, v in ipairs(solid) do local adjx, adjy = v[1], v[2] - local x, y = convertRawToScreen(v.continent, v[1], v[2], c, z) + local x, y = convertRawToScreen(v.map, v[1], v[2], m, f) --print("matchup", c, v.continent, x, y) if x and y then - local lx, ly = convertRawToScreen(v.continent, adjx + v[3], adjy + v[4], c, z) + local lx, ly = convertRawToScreen(v.map, adjx + v[3], adjy + v[4], m, f) local linemode = false - + local lidx = 5 while lidx <= #v do if type(v[lidx]) == "string" then if v[lidx] == "d" then QuestHelper: Assert(type(lidx) == "number") -- what lidx = lidx + 1 - x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z) - lx, ly = convertRawToScreen(v.continent, adjx + v[lidx + 2], adjy + v[lidx + 3], c, z) + x, y = convertRawToScreen(v.map, adjx + v[lidx], adjy + v[lidx + 1], m, f) + lx, ly = convertRawToScreen(v.map, adjx + v[lidx + 2], adjy + v[lidx + 3], m, f) lidx = lidx + 4 elseif v[lidx] == "l" then linemode = true lidx = lidx + 1 - x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z) + x, y = convertRawToScreen(v.map, adjx + v[lidx], adjy + v[lidx + 1], m, f) lx, ly = x, y lidx = lidx + 2 else @@ -571,56 +575,56 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) end else if not linemode then - local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z) - + local tx, ty = convertRawToScreen(v.map, adjx + v[lidx], adjy + v[lidx + 1], m, f) + local tri = tritarget[tristartat] if not tri then tri = CreateTriangle(parent) table.insert(tritarget, tri) end tristartat = tristartat + 1 - + tri:SetTriangle(x, y, lx, ly, tx, ty) tri:SetVertexColor(0, 0, 0, 0) tri:Show() - + lx, ly = tx, ty lidx = lidx + 2 else - local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z) - + local tx, ty = convertRawToScreen(v.map, adjx + v[lidx], adjy + v[lidx + 1], m, f) + makeline(x, y, tx, ty) - + x, y = tx, ty lidx = lidx + 2 end end end - + if linemode then makeline(x, y, lx, ly) end end end - + return tristartat, linestartat end - + function icon:SetGlow(list) local w, h = QuestHelper.map_overlay:GetWidth(), QuestHelper.map_overlay:GetHeight() - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - local zw = QuestHelper.Astrolabe:GetZoneWidth(c, z) - + local m, f = GetCurrentMapMF() + local _, _, zw = QuestHelper.Astrolabe:GetMapInfo(m, f) + local solids = {} - + local gid = 1 - for _, v in ipairs(list) do + for _, v in ipairs(list) do --print(v.cluster, v.cluster and v.cluster.solid) if v.cluster and v.cluster.solid then --print("solidified", #v.cluster.solid) solids[v.cluster.solid] = true else - local x, y = convertLocationToScreen(v.loc, c, z) + local x, y = convertLocationToScreen(v.loc, m, f) if x and y then if not self.glow_list then self.glow_list = QuestHelper:CreateTable() @@ -631,7 +635,7 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) self.glow_list[gid] = glo end gid = gid + 1 - + glo:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x*w, -y*h) glo:SetVertexColor(triangle_r, triangle_g, triangle_b, 1) glo:SetWidth(h / 20) @@ -640,10 +644,10 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) end end end - + local tid = 1 local lid = 1 - + for k, _ in pairs(solids) do if not self.triangle_list then self.triangle_list = QuestHelper:CreateTable() @@ -651,57 +655,57 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) if not self.line_list then self.line_list = QuestHelper:CreateTable() end - + tid, lid = self:CreateTriangles(k, self.triangle_list, tid, self.line_list, lid, QuestHelper.map_overlay) end -- call triangle maker here! - + if self.triangle_list then while #self.triangle_list >= tid do ReleaseTriangle(table.remove(self.triangle_list)) end - + if #self.triangle_list == 0 then QuestHelper:ReleaseTable(self.triangle_list) self.triangle_list = nil end end - + if self.glow_list then while #self.glow_list >= gid do QuestHelper:ReleaseTexture(table.remove(self.glow_list)) end - + if #self.glow_list == 0 then QuestHelper:ReleaseTable(self.glow_list) self.glow_list = nil end end - + if self.line_list then while #self.line_list >= lid do ReleaseLine(table.remove(self.line_list)) end - + if #self.line_list == 0 then QuestHelper:ReleaseTable(self.line_list) self.line_list = nil end end end - + icon.show_glow = false icon.glow_pct = 0.0 icon.phase = 0.0 icon.old_count = 0 - + function icon:OnUpdate(elapsed) self.phase = (self.phase + elapsed)%6.283185307179586476925286766559005768394338798750211641949889185 - + if self.next and self.objective and self.objective.cluster.solid and QuestHelper_Pref.zones == "next" then - - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() - if self.tri_c ~= c or self.tri_z ~= z then + + local m, f = GetCurrentMapMF() + if self.tri_m ~= m or self.tri_f ~= f then -- not entirely happy with this being here, but, welp if not self.local_triangle_list then self.local_triangle_list = QuestHelper:CreateTable() @@ -709,23 +713,23 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) if not self.local_line_list then self.local_line_list = QuestHelper:CreateTable() end - + local tid, lid = self:CreateTriangles(self.objective.cluster.solid, self.local_triangle_list, 1, self.local_line_list, 1, QuestHelper.map_overlay) - + if self.local_triangle_list then while #self.local_triangle_list >= tid do ReleaseTriangle(table.remove(self.local_triangle_list)) end end - + if self.local_line_list then while #self.local_line_list >= lid do ReleaseLine(table.remove(self.local_line_list)) end end end - - self.tri_c, self.tri_z = c, z + + self.tri_m, self.tri_f = m, f else if self.local_triangle_list then while #self.local_triangle_list > 0 do @@ -734,7 +738,7 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper:ReleaseTable(self.local_triangle_list) self.local_triangle_list = nil end - + if self.local_line_list then while #self.local_line_list > 0 do ReleaseLine(table.remove(self.local_line_list)) @@ -742,25 +746,25 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper:ReleaseTable(self.local_line_list) self.local_line_list = nil end - + self.tri_c, self.tri_z = nil, nil end - + if self.old_count > 0 then local list = QuestHelper:GetOverlapObjectives(self.objective) - + if #list ~= self.old_count then self:SetTooltip(list) self.old_count = #list self:SetGlow(list) end end - + if self.show_glow then self.glow_pct = math.min(1, self.glow_pct+elapsed*1.5) else self.glow_pct = math.max(0, self.glow_pct-elapsed*0.5) - + if self.glow_pct == 0 then if self.triangle_list then while #self.triangle_list > 0 do @@ -769,7 +773,7 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper:ReleaseTable(self.triangle_list) self.triangle_list = nil end - + if self.glow_list then while #self.glow_list > 0 do QuestHelper:ReleaseTexture(table.remove(self.glow_list)) @@ -777,7 +781,7 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper:ReleaseTable(self.glow_list) self.glow_list = nil end - + if self.line_list then while #self.line_list > 0 do ReleaseLine(table.remove(self.line_list)) @@ -785,13 +789,13 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) QuestHelper:ReleaseTable(self.line_list) self.line_list = nil end - + if not self.next then QH_Hook(self, "OnUpdate", nil) end end end - + if self.triangle_list then for _, tri in ipairs(self.triangle_list) do tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity/2) @@ -804,7 +808,7 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) end if self.glow_list then for _, tri in ipairs(self.glow_list) do - tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity) + tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity) end end if self.local_triangle_list then @@ -818,25 +822,25 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) end end end - + function icon:OnEnter() local list = QuestHelper:GetOverlapObjectives(self.objective) self:SetTooltip(list) self.old_count = #list - + icon.show_glow = true - + self:SetGlow(list) - + QH_Hook(self, "OnUpdate", self.OnUpdate) end - + function icon:OnLeave() QuestHelper.tooltip:Hide() self.show_glow = false self.old_count = 0 end - + function icon:OnEvent() if self.objective then QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(self.objective.loc)) @@ -845,20 +849,20 @@ function QuestHelper:CreateWorldMapDodad(objective, nxt) self:Hide() end end - + function icon:OnClick() rightclick_menu(self.objective) end - + QH_Hook(icon, "OnClick", icon.OnClick) QH_Hook(icon, "OnEnter", icon.OnEnter) QH_Hook(icon, "OnLeave", icon.OnLeave) QH_Hook(icon, "OnEvent", icon.OnEvent) - + icon:RegisterForClicks("RightButtonUp") - + QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end) - + icon:SetObjective(objective, nxt) return icon end @@ -867,68 +871,68 @@ end function QuestHelper:CreateWorldMapMinidad(objective, nxt) local icon = CreateFrame("Button", nil, QuestHelper.map_overlay) icon:SetFrameStrata("FULLSCREEN") - + function icon:SetPosition(objective) self:SetHeight(16*QuestHelper_Pref.scale) self:SetWidth(16*QuestHelper_Pref.scale) - + if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end - + if objective then self.objective = objective - + self.dot = QuestHelper:CreateIconTexture(self, 15) self.dot:SetAllPoints() self.dot:SetDrawLayer("BACKGROUND") - - QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, QuestHelper.Astrolabe:FromAbsoluteContinentPosition(QuestHelper_ParentLookup[self.objective.p], self.objective.x, self.objective.y)) + + QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, self.objective.m, self.objective.f, self.objective.x, self.objective.y) else self.objective = nil self:Hide() end end - - + + function icon:OnEnter() local list = QuestHelper:GetOverlapObjectives(self.objective) self.old_count = #list QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR") QuestHelper.tooltip:ClearLines() - + QuestHelper.tooltip:AddLine(self.objective.desc) - + QuestHelper.tooltip:Show() end - + function icon:OnLeave() QuestHelper.tooltip:Hide() end - + function icon:OnEvent() if self.objective then - QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, QuestHelper.Astrolabe:FromAbsoluteContinentPosition(QuestHelper_ParentLookup[self.objective.p], self.objective.x, self.objective.y)) + QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, self.objective.m, self.objective.f, self.objective.x, self.objective.y) else self.objective = nil self:Hide() end end - + --function icon:OnClick() --rightclick_menu(self.objective) --end - + --QH_Hook(icon, "OnClick", icon.OnClick) QH_Hook(icon, "OnEnter", icon.OnEnter) QH_Hook(icon, "OnLeave", icon.OnLeave) QH_Hook(icon, "OnEvent", icon.OnEvent) - + --icon:RegisterForClicks("RightButtonUp") - + QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end) - + icon:SetPosition(objective) return icon end @@ -948,11 +952,11 @@ function QuestHelper:AddWaypointCallback(func, ...) cb[len+3] = last_x cb[len+4] = last_y cb[len+5] = last_desc - + if last_c then func(unpack(cb, 1, len+5)) end - + return cb end @@ -967,7 +971,7 @@ function QuestHelper:InvokeWaypointCallbacks(c, z, x, y, desc) QuestHelper: Assert(not x or type(x) == "number") QuestHelper: Assert(not y or type(y) == "number") if c == last_c and z == last_z and desc == last_desc and not x and not y then x, y = last_x, last_y end -- sometimes we may not have up-to-date location, but could still in theory be pointing at the same spot - + if not c or (x and y) then if c ~= last_c or z ~= last_z or x ~= last_x or y ~= last_y or desc ~= last_desc then last_c, last_z, last_x, last_y, last_desc = c, z, x, y, desc @@ -984,12 +988,14 @@ function QuestHelper:InvokeWaypointCallbacks(c, z, x, y, desc) end end +--[[ According to grep, there are no calls to this function. function QuestHelper:SetMinimapObject(minimap) Minimap = minimap QuestHelper.Astrolabe:SetMinimapObject(minimap) QuestHelper.minimap_marker:SetParent(minimap) QuestHelper.Astrolabe.processingFrame:SetParent(minimap) end +--]] --[[ Small parts of the arrow rendering code are thanks to Tomtom, with the following license: @@ -1007,7 +1013,7 @@ end copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * The name or alias of the copyright holder may not be used to endorse + * The name or alias of the copyright holder may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -1028,21 +1034,21 @@ function QuestHelper:CreateMipmapDodad() local icon = CreateFrame("Button", nil, Minimap) icon:Hide() icon.recalc_timeout = 0 - + icon.arrow = icon:CreateTexture("BACKGROUND") icon.arrow:SetHeight(40) icon.arrow:SetWidth(40) icon.arrow:SetPoint("CENTER", 0, 0) icon.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\MinimapArrow") icon.arrow:Hide() - + icon.phase = 0 icon.target = {0, 0, 0, 0} - + icon.bg = QuestHelper:CreateIconTexture(icon, 16) icon.bg:SetDrawLayer("BACKGROUND") icon.bg:SetAllPoints() - + function icon:OnUpdate(elapsed) local c, z, x, y, textdesc if self.obj then @@ -1050,32 +1056,32 @@ function QuestHelper:CreateMipmapDodad() if c and z then x, y = convertLocationToScreen(self.obj.loc, c, z) end - + if self.obj.map_desc_chain then -- the first line will just be an "enroute" line textdesc = (self.obj.arrow_desc or self.obj.map_desc[1]) .. "\n" .. (self.obj.map_desc_chain.arrow_desc or self.obj.map_desc_chain.map_desc[1]) else textdesc = (self.obj.arrow_desc or self.obj.map_desc[1]) end - + if self.obj.arrow_desc then textdesc = self.obj.arrow_desc end end - + QuestHelper: Assert(not c or type(c) == "number") QuestHelper: Assert(not z or type(z) == "number") - + -- Deal with waypoint callbacks if QuestHelper_Pref.hide or UnitIsDeadOrGhost("player") and not QuestHelper.InBrokenInstance then QuestHelper:InvokeWaypointCallbacks() else QuestHelper:InvokeWaypointCallbacks(c, z, x, y, textdesc) end - + if self.obj and not QuestHelper.InBrokenInstance then self:Show() -- really only triggers if the non-broken-instance code is being poked - + QuestHelper: Assert(self, "Missing self.") -- Yeah right. QuestHelper: Assert(self.obj, "Missing objective.") QuestHelper: Assert(self.obj.loc, "Missing Location.") @@ -1085,7 +1091,7 @@ function QuestHelper:CreateMipmapDodad() if not QuestHelper_Pref.hide and QuestHelper.Astrolabe:PlaceIconOnMinimap(self, convertLocation(self.obj.loc)) ~= -1 then local edge = QuestHelper.Astrolabe:IsIconOnEdge(self) - + if edge then self.arrow:Show() self.dot:Hide() @@ -1094,17 +1100,17 @@ function QuestHelper:CreateMipmapDodad() self.arrow:Hide() self.dot:Show() self.bg:Show() - + self.dot:SetAlpha(QuestHelper_Pref.mini_opacity) self.bg:SetAlpha(QuestHelper_Pref.mini_opacity) end - + if edge then local angle = QuestHelper.Astrolabe:GetDirectionToIcon(self) if GetCVar("rotateMinimap") == "1" then - angle = angle + QuestHelper.Astrolabe:GetFacing() + angle = angle - GetPlayerFacing() end - + if elapsed then if self.phase > 6.283185307179586476925 then self.phase = self.phase-6.283185307179586476925+elapsed*3.5 @@ -1112,9 +1118,9 @@ function QuestHelper:CreateMipmapDodad() self.phase = self.phase+elapsed*3.5 end end - + local scale = 1.0 + 0.1 * math.sin(self.phase) - + local x, y = scale * math.sin(angle + 3.14159 * 0.75) * math.sqrt(0.5), scale * math.cos(angle + 3.14159 * 0.75) * math.sqrt(0.5) self.arrow:SetTexCoord(0.5 - x, 0.5 + y, 0.5 + y, 0.5 + x, 0.5 - y, 0.5 - x, 0.5 + x, 0.5 - y) end @@ -1125,7 +1131,7 @@ function QuestHelper:CreateMipmapDodad() self:Hide() end end - + function icon:SetObjective(obj) if obj then QuestHelper: Assert(obj.loc, "Objective has no location data.") @@ -1135,47 +1141,47 @@ function QuestHelper:CreateMipmapDodad() end self:SetHeight(20*QuestHelper_Pref.scale) self:SetWidth(20*QuestHelper_Pref.scale) - + if obj ~= self.obj then self.obj = obj - + self.recalc_timeout = 0 - + if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end - + if self.obj then self.dot = QuestHelper:CreateIconTexture(self, self.obj.icon_id or 8) self.dot:SetPoint("TOPLEFT", icon, "TOPLEFT", 2, -2) self.dot:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -2, 2) end - + self:OnUpdate(0) end end - + function icon:OnEnter() if self.obj then QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR") QuestHelper.tooltip:ClearLines() - + --[[if self.target[5] then QuestHelper.tooltip:AddLine(QHFormat("WAYPOINT_REASON", self.target[5]), unpack(QuestHelper:GetColourTheme().tooltip)) QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.serif, 14) end]] - + QuestHelper:AppendObjectiveToTooltip(self.obj) QuestHelper.tooltip:Show() end end - + function icon:OnLeave() QuestHelper.tooltip:Hide() end - + function icon:OnClick() rightclick_menu(self.obj) end - + function icon:OnEvent() if self.obj then self:Show() @@ -1183,15 +1189,15 @@ function QuestHelper:CreateMipmapDodad() self:Hide() end end - + QH_Hook(icon, "OnUpdate", icon.OnUpdate) QH_Hook(icon, "OnEnter", icon.OnEnter) QH_Hook(icon, "OnLeave", icon.OnLeave) QH_Hook(icon, "OnClick", icon.OnClick) - + icon:RegisterForClicks("RightButtonUp") - + QH_Event("PLAYER_ENTERING_WORLD", function () icon:OnEvent() end) - + return icon end diff --git a/QuestHelper/manager_completed.lua b/QuestHelper/manager_completed.lua index 5be7962..bffc81b 100644 --- a/QuestHelper/manager_completed.lua +++ b/QuestHelper/manager_completed.lua @@ -50,7 +50,7 @@ local poll_first = true QH_Event("QUEST_QUERY_COMPLETE", function () quests = GetQuestsCompleted() -- entertainingly, we actually want exactly the output of this. How convenient! Blizzard does things right <3 forever - + notify() end) @@ -85,16 +85,16 @@ local waypoint_zone function rescan() if not waypoint_zone then return end if not QuestHelper.Astrolabe.WorldMapVisible then return end - + QH_POI_Reset() - + if not completed_active then return end - + local questlist = DB_GetItem("questlist", waypoint_zone, true) if not questlist then return end - + local donequests = QH_GetCompletedTable() - + for _, v in ipairs(questlist) do if donequests[v] then --print("Done:", v) @@ -110,13 +110,13 @@ function rescan() end QH_AddCompletionNotifier(rescan) -QH_Event("WORLD_MAP_UPDATE", function () - local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ() +QH_Event("WORLD_MAP_UPDATE", function () -- NOTE: WILL NOT WORK UNTIL UPGRADE.LUA IS FIXED + local m, f = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() --print(c, z) if not QuestHelper_IndexLookup[c] or not QuestHelper_IndexLookup[c][z] then return end QuestHelper: Assert(QuestHelper_IndexLookup[c]) QuestHelper: Assert(QuestHelper_IndexLookup[c][z]) waypoint_zone = QuestHelper_IndexLookup[c][z] - + rescan() end) diff --git a/QuestHelper/objective.lua b/QuestHelper/objective.lua index 1da641c..5520898 100644 --- a/QuestHelper/objective.lua +++ b/QuestHelper/objective.lua @@ -16,26 +16,26 @@ local UserIgnored = { function QuestHelper:AddObjectiveOptionsToMenu(obj, menu) local submenu = self:CreateMenu() - + local pri = (QH_Route_GetClusterPriority(obj.cluster) or 0) + 3 for i = 1, 5 do local name = QHText("PRIORITY"..i) local item = self:CreateMenuItem(submenu, name) local tex - + if pri == i then tex = self:CreateIconTexture(item, 10) else tex = self:CreateIconTexture(item, 12) tex:SetVertexColor(1, 1, 1, 0) end - + item:AddTexture(tex, true) item:SetFunction(QH_Route_SetClusterPriority, obj.cluster, i - 3) end - + self:CreateMenuItem(menu, QHText("PRIORITY")):SetSubmenu(submenu) - + --[[if self.sharing then submenu = self:CreateMenu() local item = self:CreateMenuItem(submenu, QHText("SHARING_ENABLE")) @@ -43,25 +43,25 @@ function QuestHelper:AddObjectiveOptionsToMenu(obj, menu) if not obj.want_share then tex:SetVertexColor(1, 1, 1, 0) end item:AddTexture(tex, true) item:SetFunction(obj.Share, obj) - + local item = self:CreateMenuItem(submenu, QHText("SHARING_DISABLE")) local tex = self:CreateIconTexture(item, 10) if obj.want_share then tex:SetVertexColor(1, 1, 1, 0) end item:AddTexture(tex, true) item:SetFunction(obj.Unshare, obj) - + self:CreateMenuItem(menu, QHText("SHARING")):SetSubmenu(submenu) end]] - + --self:CreateMenuItem(menu, "(No options available)") - + if not obj.map_suppress_ignore then self:CreateMenuItem(menu, QHText("IGNORE")):SetFunction(function () QH_Route_IgnoreCluster(obj.cluster, UserIgnored) end) -- There is probably a nasty race condition here. I'm not entirely happy about it. end if obj.map_custom_menu then obj.map_custom_menu(menu) end - + if obj.cluster and #obj.cluster > 1 and QH_Route_Ignored_Cluster_Active(obj.cluster) > 1 then self:CreateMenuItem(menu, QHText("IGNORE_LOCATION")):SetFunction(QH_Route_IgnoreNode, obj, UserIgnored) end @@ -73,13 +73,13 @@ local function ObjectiveCouldBeFirst(self) if (self.user_ignore == nil and self.auto_ignore) or self.user_ignore then return false end - + for i, j in pairs(self.after) do if i.watched then return false end end - + return true end @@ -95,13 +95,13 @@ local function DefaultObjectiveKnown(self) elseif self.user_ignore then return false end - + for i, j in pairs(self.after) do if i.watched and not i:Known() then -- Need to know how to do everything before this objective. return false end end - + return true end @@ -114,30 +114,30 @@ local function ObjectiveReason(self, short) end end end - + if not reason then reason = "Do some extremely secret unspecified something." end - + if not short and self.pos and self.pos[6] then reason = reason .. "\n" .. self.pos[6] end - + return reason end local function Uses(self, obj, text) if self == obj then return end -- You cannot use yourself. A purse is not food. local uses, used = self.uses, obj.used - + if not uses then uses = QuestHelper:CreateTable("uses") self.uses = uses end - + if not used then used = QuestHelper:CreateTable("used") obj.used = used end - + if not uses[obj] then uses[obj] = true used[self] = text @@ -162,26 +162,26 @@ end local function MarkUnused(self) --[[ assert(self.marked_used) ]] - + if self.marked_used == 1 then local uses = self.uses - + if uses then for obj in pairs(uses) do obj.used[self] = nil obj:MarkUnused() end - + QuestHelper:ReleaseTable(uses) self.uses = nil end - + if self.used then --[[ assert(not next(self.used)) ]] QuestHelper:ReleaseTable(self.used) self.used = nil end - + self.marked_used = nil else self.marked_used = self.marked_used - 1 @@ -194,7 +194,7 @@ end local function ItemKnown(self) if not DefaultObjectiveKnown(self) then return false end - + if self.o.vendor then for i, npc in ipairs(self.o.vendor) do local n = self.qh:GetObjective("monster", npc) @@ -204,7 +204,7 @@ local function ItemKnown(self) end end end - + if self.fb.vendor then for i, npc in ipairs(self.fb.vendor) do local n = self.qh:GetObjective("monster", npc) @@ -214,40 +214,40 @@ local function ItemKnown(self) end end end - + if self.o.pos or self.fb.pos then return true end - + if self.o.drop then for monster in pairs(self.o.drop) do if self.qh:GetObjective("monster", monster):Known() then return true end end end - + if self.fb.drop then for monster in pairs(self.fb.drop) do if self.qh:GetObjective("monster", monster):Known() then return true end end end - + if self.o.contained then for item in pairs(self.o.contained) do if self.qh:GetObjective("item", item):Known() then return true end end end - + if self.fb.contained then for item in pairs(self.fb.contained) do if self.qh:GetObjective("item", item):Known() then return true end end end - + if self.quest then local item=self.quest.o.item item = item and item[self.obj] - - if item then + + if item then if item.pos then return true end @@ -259,10 +259,10 @@ local function ItemKnown(self) end end end - + item=self.quest.fb.item item = item and item[self.obj] - if item then + if item then if item.pos then return true end @@ -275,29 +275,29 @@ local function ItemKnown(self) end end end - + return false end local function ObjectiveAppendPositions(self, objective, weight, why, restrict) local high = 0 - + if self.o.pos then for i, p in ipairs(self.o.pos) do high = math.max(high, p[4]) end end - + if self.fb.pos then for i, p in ipairs(self.fb.pos) do high = math.max(high, p[4]) end end - + high = weight/high - + if self.o.pos then for i, p in ipairs(self.o.pos) do if not restrict or not self.qh:Disallowed(p[1]) then objective:AddLoc(p[1], p[2], p[3], p[4]*high, why) end end end - + if self.fb.pos then for i, p in ipairs(self.fb.pos) do if not restrict or not self.qh:Disallowed(p[1]) then objective:AddLoc(p[1], p[2], p[3], p[4]*high, why) @@ -314,34 +314,34 @@ local function ObjectivePrepareRouting(self, anywhere) --[[ assert(not self.nm) ]] --[[ assert(not self.nm2) ]] --[[ assert(not self.nl) ]] - + self.d = QuestHelper:CreateTable("objective.d") self.p = QuestHelper:CreateTable("objective.p") self.nm = QuestHelper:CreateTable("objective.nm") self.nm2 = QuestHelper:CreateTable("objective.nm2") self.nl = QuestHelper:CreateTable("objective.nl") self.distance_cache = QuestHelper:CreateTable("objective.distance_cache") - + if not anywhere then self:AppendPositions(self, 1, nil, true) - + if not next(self.p) then QuestHelper:TextOut(QHFormat("INACCESSIBLE_OBJ", self.obj or "whatever it was you just requested")) anywhere = true end end - + if anywhere then self:AppendPositions(self, 1, nil, false) end - + self:FinishAddLoc(args) end end local function ItemAppendPositions(self, objective, weight, why, restrict) why2 = why and why.."\n" or "" - + if self.o.vendor then for i, npc in ipairs(self.o.vendor) do local n = self.qh:GetObjective("monster", npc) local faction = n.o.faction or n.fb.faction @@ -349,7 +349,7 @@ local function ItemAppendPositions(self, objective, weight, why, restrict) n:AppendPositions(objective, 1, why2..QHFormat("OBJECTIVE_PURCHASE", npc), restrict) end end end - + if self.fb.vendor then for i, npc in ipairs(self.fb.vendor) do local n = self.qh:GetObjective("monster", npc) local faction = n.o.faction or n.fb.faction @@ -357,45 +357,45 @@ local function ItemAppendPositions(self, objective, weight, why, restrict) n:AppendPositions(objective, 1, why2..QHFormat("OBJECTIVE_PURCHASE", npc), restrict) end end end - + if next(objective.p, nil) then -- If we have points from vendors, then always use vendors. I don't want it telling you to killing the -- towns people just because you had to talk to them anyway, and it saves walking to the store. return end - + if self.o.drop then for monster, count in pairs(self.o.drop) do local m = self.qh:GetObjective("monster", monster) m:AppendPositions(objective, m.o.looted and count/m.o.looted or 1, why2..QHFormat("OBJECTIVE_SLAY", monster), restrict) end end - + if self.fb.drop then for monster, count in pairs(self.fb.drop) do local m = self.qh:GetObjective("monster", monster) m:AppendPositions(objective, m.fb.looted and count/m.fb.looted or 1, why2..QHFormat("OBJECTIVE_SLAY", monster), restrict) end end - + if self.o.contained then for item, count in pairs(self.o.contained) do local i = self.qh:GetObjective("item", item) i:AppendPositions(objective, i.o.opened and count/i.o.opened or 1, why2..QHFormat("OBJECTIVE_LOOT", item), restrict) end end - + if self.fb.contained then for item, count in pairs(self.fb.contained) do local i = self.qh:GetObjective("item", item) i:AppendPositions(objective, i.fb.opened and count/i.fb.opened or 1, why2..QHFormat("OBJECTIVE_LOOT", item), restrict) end end - + if self.o.pos then for i, p in ipairs(self.o.pos) do if not restrict or not self.qh:Disallowed(p[1]) then objective:AddLoc(p[1], p[2], p[3], p[4], why) end end end - + if self.fb.pos then for i, p in ipairs(self.fb.pos) do if not restrict or not self.qh:Disallowed(p[1]) then objective:AddLoc(p[1], p[2], p[3], p[4], why) end end end - + if self.quest then local item_list=self.quest.o.item if item_list then @@ -413,9 +413,9 @@ local function ItemAppendPositions(self, objective, weight, why, restrict) end end end - + item_list=self.quest.fb.item - if item_list then + if item_list then local data = item_list[self.obj] if data and data.drop then for monster, count in pairs(data.drop) do @@ -441,7 +441,7 @@ local function ItemDoMarkUsed(self) self:Uses(n, "TOOLTIP_PURCHASE") end end end - + if self.fb.vendor then for i, npc in ipairs(self.fb.vendor) do local n = self.qh:GetObjective("monster", npc) local faction = n.o.faction or n.fb.faction @@ -449,23 +449,23 @@ local function ItemDoMarkUsed(self) self:Uses(n, "TOOLTIP_PURCHASE") end end end - + if self.o.drop then for monster, count in pairs(self.o.drop) do self:Uses(self.qh:GetObjective("monster", monster), "TOOLTIP_SLAY") end end - + if self.fb.drop then for monster, count in pairs(self.fb.drop) do self:Uses(self.qh:GetObjective("monster", monster), "TOOLTIP_SLAY") end end - + if self.o.contained then for item, count in pairs(self.o.contained) do self:Uses(self.qh:GetObjective("item", item), "TOOLTIP_LOOT") end end - + if self.fb.contained then for item, count in pairs(self.fb.contained) do self:Uses(self.qh:GetObjective("item", item), "TOOLTIP_LOOT") end end - + if self.quest then local item_list=self.quest.o.item if item_list then @@ -476,9 +476,9 @@ local function ItemDoMarkUsed(self) end end end - + item_list=self.quest.fb.item - if item_list then + if item_list then local data = item_list[self.obj] if data and data.drop then for monster, count in pairs(data.drop) do @@ -511,27 +511,27 @@ end - +-- NEEDS CONVERSION FOR Map, Floor. local function AddLoc(self, index, x, y, w, why) --[[ assert(not self.setup) ]] - + if w > 0 then local pair = QuestHelper_ZoneLookup[index] QuestHelper: Assert(pair, "Index does not exist... it is probably 26 or 38 and the value really is... '" .. tostring(index) .. "'") if not pair then return end -- that zone doesn't exist! We require more vespene gas. Not enough rage! local c, z = pair[1], pair[2] x, y = self.qh.Astrolabe:TranslateWorldMapPosition(c, z, x, y, c, 0) - + x = x * self.qh.continent_scales_x[c] y = y * self.qh.continent_scales_y[c] local list = self.qh.zone_nodes[index] - + local points = self.p[list] if not points then points = QuestHelper:CreateTable("objective.p[zone] (objective nodes per-zone)") self.p[list] = points end - + for i, p in pairs(points) do local u, v = x-p[3], y-p[4] if u*u+v*v < 25 then -- Combine points within a threshold of 5 seconds travel time. @@ -544,7 +544,7 @@ local function AddLoc(self, index, x, y, w, why) return end end - + local new = QuestHelper:CreateTable("objective.p[zone] (possible objective node)") new[1], new[2], new[3], new[4], new[5], new[6], new[7] = list, nil, x, y, w, why, w table.insert(points, new) @@ -553,7 +553,7 @@ end local function FinishAddLoc(self, args) local mx = 0 - + for z, pl in pairs(self.p) do for i, p in ipairs(pl) do if p[5] > mx then @@ -562,7 +562,7 @@ local function FinishAddLoc(self, args) end end end - + if not self.zones then -- Not using CreateTable, because it will not be released when routing is complete. self.zones = {} @@ -570,7 +570,7 @@ local function FinishAddLoc(self, args) -- We could remove the already known zones, but I'm operating under the assumtion that locations will only be added, -- not removed, so this isn't necessary. end - + -- Remove probably useless locations. for z, pl in pairs(self.p) do local remove_zone = true @@ -591,25 +591,25 @@ local function FinishAddLoc(self, args) self.zones[z.i] = true end end - + local node_map = self.nm local node_list = self.nl - + for list, pl in pairs(self.p) do local dist = self.d[list] - + --[[ assert(not dist) ]] - + if not dist then dist = QuestHelper:CreateTable("self.d[list]") self.d[list] = dist end - + for i, point in ipairs(pl) do point[5] = mx/point[5] -- Will become 1 for the most desired location, and become larger and larger for less desireable locations. - + point[2] = QuestHelper:CreateTable("possible objective node to zone edge cache") - + for i, node in ipairs(list) do QuestHelper: Assert(type(point[3]) == "number", string.format("p3 %s", tostring(point[3]))) QuestHelper: Assert(type(point[4]) == "number", string.format("p4 %s", tostring(point[4]))) @@ -617,9 +617,9 @@ local function FinishAddLoc(self, args) QuestHelper: Assert(type(node.y) == "number", string.format("ny %s", tostring(node.y))) local u, v = point[3]-node.x, point[4]-node.y local d = math.sqrt(u*u+v*v) - + point[2][i] = d - + if dist[i] then if d*point[5] < dist[i][1]*dist[i][2] then dist[i][1], dist[i][2] = d, point[5] @@ -629,13 +629,13 @@ local function FinishAddLoc(self, args) local pair = QuestHelper:CreateTable() pair[1], pair[2] = d, point[5] dist[i] = pair - + if not node_map[node] then table.insert(node_list, node) node_map[node] = point else u, v = node_map[node][3]-node.x, node_map[node][4]-node.y - + if dist[i][1]*dist[i][2] < math.sqrt(u*u+v*v)*node_map[node][5] then node_map[node] = point end @@ -644,12 +644,12 @@ local function FinishAddLoc(self, args) end end end - + -- Disabled because we're having some data sanity issues. This should be solved at buildtime, but I'm leery of mucking with the build system right now, so it isn't. Re-enable later. --if not args or not args.failable then -- if #node_list == 0 and QuestHelper:IsWrath() then QuestHelper:Error(self.cat.."/"..self.obj..": zero nodes!") end --end - + --[[ assert(not self.setup) ]] self.setup = true table.insert(self.qh.prepared_objectives, self) @@ -657,7 +657,7 @@ end local function GetPosition(self) --[[ assert(self.setup) ]] - + return self.location end @@ -667,7 +667,7 @@ local QH_TESTCACHE = nil -- make this "true" or something if you want to test c -- More annotation here, if you're trying to learn the codebase. This function is a more complicated version of QH:ComputeTravelTime, so refer to that for information first before reading this one. local function ObjectiveTravelTime(self, pos, nocache) --[[ assert(self.setup) ]] - + -- The caching is pretty obvious. local key, cached if not nocache then @@ -686,9 +686,9 @@ local function ObjectiveTravelTime(self, pos, nocache) local graph = self.qh.world_graph local nl = self.nl - + graph:PrepareSearch() - + -- This is quite similar to the same "create nodes for all zone links" in ComputeTravelTime except that it's creating nodes for all zone links for a set of possible destinations. I'm not sure if the weighting is backwards. It might be. for z, l in pairs(self.d) do for i, n in ipairs(z) do @@ -700,24 +700,24 @@ local function ObjectiveTravelTime(self, pos, nocache) end end end - + local d = pos[2] for i, n in ipairs(pos[1]) do graph:AddStartNode(n, d[i], nl) end - + local e = graph:DoSearch(nl) - + -- d changes datatype here. I hate this codebase. Hell, e probably changes datatype also! yaaaay. what does .nm mean? what does .d mean? d = e.g+e.e e = self.nm[e] - + -- There's something going on with weighting here that I don't understand local l = self.p[pos[1]] if l then local x, y = pos[3], pos[4] local score = d*e[5] - + for i, n in ipairs(l) do local u, v = x-n[3], y-n[4] local d2 = math.sqrt(u*u+v*v) @@ -727,7 +727,7 @@ local function ObjectiveTravelTime(self, pos, nocache) end end end - + --[[ assert(e) ]] if not nocache then --[[ assert( not cached or (cached[1] == d and cached[2] == e)) ]] @@ -750,7 +750,7 @@ end -- Yet more annotation! This one is based off ObjectiveTravelTime. Yes, it's nasty that there are three (edit: four) functions with basically the same goal. Have I mentioned this codebase kind of sucks? local function ObjectiveTravelTime2(self, pos1, pos2, nocache) --[[ assert(self.setup) ]] - + -- caching is pretty simple as usual local key, cached if not nocache then @@ -774,10 +774,10 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) local graph = self.qh.world_graph local nl = self.nl - + -- This is the standard pos1-to-self code that we're used to seeing . . . graph:PrepareSearch() - + for z, l in pairs(self.d) do for i, n in ipairs(z) do if n.s == 0 then @@ -788,23 +788,23 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) end end end - + local d = pos1[2] for i, n in ipairs(pos1[1]) do graph:AddStartNode(n, d[i], nl) end - + graph:DoFullSearch(nl) - + graph:PrepareSearch() - + -- . . . and here's where it gets wonky -- Now, we need to figure out how long it takes to get to each node. for z, point_list in pairs(self.p) do if z == pos1[1] then -- Will also consider min distance. local x, y = pos1[3], pos1[4] - + for i, p in ipairs(point_list) do local a, b = p[3]-x, p[4]-y local u, v = p[3], p[4] @@ -827,7 +827,7 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) local w = p[5] local d local score - + for i, n in ipairs(z) do local a, b = n.x-x, n.y-y local d2 = math.sqrt(a*a+b*b)+n.g @@ -840,17 +840,17 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) end end end - + d = pos2[2] - + for i, n in ipairs(pos2[1]) do n.e = d[i] n.s = 3 end - + local el = pos2[1] local nm = self.nm2 - + for z, l in pairs(self.d) do for i, n in ipairs(z) do local x, y = n.x, n.y @@ -865,21 +865,21 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) bg, bp, bs = d, p, s end end - + nm[n] = bp -- Using score instead of distance, because we want nodes we're not really interested in to be less likely to get chosen. graph:AddStartNode(n, bs, el) end end - + local e = graph:DoSearch(pos2[1]) - + d = nm[e.p][7] local d2 = e.g+e.e-e.p.g+(e.p.g/nm[e.p][5]-nm[e.p][7]) - + e = nm[e.p] local total = (d+d2)*e[5] - + if self.p[el] then local x, y = pos2[3], pos2[4] for i, p in ipairs(self.p[el]) do @@ -891,7 +891,7 @@ local function ObjectiveTravelTime2(self, pos1, pos2, nocache) end end end - + -- grim stabilization hack, since obviously the numbers it generates are only vaguely based in reality. This should be fixed and removed ASAP (you know, once I figure out WTF this thing is doing) d = QuestHelper:ComputeTravelTime(pos1, e) d2 = QuestHelper:ComputeTravelTime(e, pos2) @@ -941,7 +941,7 @@ end local function DoneRouting(self) --[[ assert(self.setup_count > 0) ]] --[[ assert(self.setup) ]] - + if self.setup_count == 1 then self.setup_count = 0 QuestHelper:ReleaseObjectivePathingInfo(self) @@ -1001,28 +1001,28 @@ end QuestHelper.default_objective_param = { CouldBeFirst=ObjectiveCouldBeFirst, - + Uses=Uses, DoMarkUsed=DoMarkUsed, MarkUsed=MarkUsed, MarkUnused=MarkUnused, - + DefaultKnown=DefaultObjectiveKnown, Known=DummyObjectiveKnown, Reason=ObjectiveReason, - + AppendPositions=ObjectiveAppendPositions, PrepareRouting=ObjectivePrepareRouting, AddLoc=AddLoc, FinishAddLoc=FinishAddLoc, DoneRouting=DoneRouting, - + Position=GetPosition, TravelTime=ObjectiveTravelTime, TravelTime2=ObjectiveTravelTime2, IsWatched=IsObjectiveWatched, - + Share=ObjectiveShare, -- Invoke to share this objective with your peers. Unshare=ObjectiveUnshare, -- Invoke to stop sharing this objective. } @@ -1049,29 +1049,29 @@ function QuestHelper:NewObjectiveObject() setmetatable({ qh=self, id=next_objective_id, - + want_share=false, -- True if we want this objective shared. is_sharing=false, -- Set to true if we've told other users about this objective. - + user_ignore=nil, -- When nil, will use filters. Will ignore, when true, always show (if known). - + priority=3, -- A hint as to what priority the quest should have. Should be 1, 2, 3, 4, or 5. real_priority=3, -- This will be set to the priority routing actually decided to assign it. - + setup_count=0, - + icon_id=12, icon_bg=14, - + match_zone=false, match_level=false, match_done=false, - + before={}, -- List of objectives that this objective must appear before. after={}, -- List of objectives that this objective must appear after. - + -- Routing related junk. - + --[[ Will be created as needed. d=nil, p=nil, @@ -1088,14 +1088,14 @@ local explicit_support_warning_given = false function QuestHelper:GetObjective(category, objective) local objective_list = self.objective_objects[category] - + if not objective_list then objective_list = {} self.objective_objects[category] = objective_list end - + local objective_object = objective_list[objective] - + if not objective_object then if category == "quest" then local level, hash, name = string.match(objective, "^(%d+)/(%d*)/(.*)$") @@ -1105,18 +1105,18 @@ function QuestHelper:GetObjective(category, objective) name = objective end end - + if hash == "" then hash = nil end objective_object = self:GetQuest(name, tonumber(level), tonumber(hash)) objective_list[objective] = objective_object return objective_object end - + objective_object = self:NewObjectiveObject() - + objective_object.cat = category objective_object.obj = objective - + if category == "item" then setmetatable(objective_object, QuestHelper.default_objective_item_meta) objective_object.icon_id = 2 @@ -1138,21 +1138,21 @@ function QuestHelper:GetObjective(category, objective) explicit_support_warning_given = true end end - + objective_list[objective] = objective_object - + if category == "loc" then -- Loc is special, we don't store it, and construct it from the string. -- Don't have any error checking here, will assume it's correct. local i local _, _, c, z, x, y = string.find(objective,"^(%d+),(%d+),([%d%.]+),([%d%.]+)$") - + if not y then _, _, i, x, y = string.find(objective,"^(%d+),([%d%.]+),([%d%.]+)$") else i = QuestHelper_IndexLookup[c][z] end - + objective_object.o = {pos={{tonumber(i),tonumber(x),tonumber(y),1}}} objective_object.fb = {} else @@ -1176,18 +1176,18 @@ function QuestHelper:GetObjective(category, objective) if not objective_object.fb then objective_object.fb = {} end - + -- TODO: If we have some other source of information (like LightHeaded) add its data to objective_object.fb - + end end - + return objective_object end function QuestHelper:AppendObjectivePosition(objective, i, x, y, w) if not i then return end -- We don't have a player position. We have a pile of poop. Enjoy your poop. - + local pos = objective.o.pos if not pos then if objective.o.drop or objective.o.contained then @@ -1248,11 +1248,11 @@ function QuestHelper:AddObjectiveWatch(objective, reason) if not objective.reasons then objective.reasons = {} end - + if not next(objective.reasons, nil) then objective.watched = true objective:MarkUsed() - + objective.filter_blocked = false for obj in pairs(objective.swap_after or objective.after) do if obj.watched then @@ -1260,20 +1260,20 @@ function QuestHelper:AddObjectiveWatch(objective, reason) break end end - + for obj in pairs(objective.swap_before or objective.before) do if obj.watched then obj.filter_blocked = true end end - + if self.to_remove[objective] then self.to_remove[objective] = nil else self.to_add[objective] = true end end - + objective.reasons[reason] = (objective.reasons[reason] or 0) + 1 end @@ -1283,7 +1283,7 @@ function QuestHelper:RemoveObjectiveWatch(objective, reason) if not next(objective.reasons, nil) then objective:MarkUnused() objective.watched = false - + for obj in pairs(objective.swap_before or objective.before) do if obj.watched then obj.filter_blocked = false @@ -1295,7 +1295,7 @@ function QuestHelper:RemoveObjectiveWatch(objective, reason) end end end - + if self.to_add[objective] then self.to_add[objective] = nil else @@ -1310,13 +1310,13 @@ end function QuestHelper:ObjectiveObjectDependsOn(objective, needs) --[[ assert(objective ~= needs) ]] -- If this was true, ObjectiveIsKnown would get in an infinite loop. -- TODO: Needs sanity checking, especially now that dependencies can be assigned by remote users. - - + + -- We store the new relationships in objective.swap_[before|after], -- creating and copying them from objective.[before|after], -- the routing coroutine will check for those, swap them, and release the originals -- when it gets to a safe place to do so. - + if not (objective.swap_after or objective.after)[needs] then if objective.peer then for u, l in pairs(objective.peer) do @@ -1324,21 +1324,21 @@ function QuestHelper:ObjectiveObjectDependsOn(objective, needs) objective.peer[u] = math.min(l, 1) end end - + if not objective.swap_after then objective.swap_after = self:CreateTable("swap_after") for key,value in pairs(objective.after) do objective.swap_after[key] = value end end - + if not needs.swap_before then needs.swap_before = self:CreateTable("swap_before") for key,value in pairs(needs.before) do needs.swap_before[key] = value end end - + if needs.watched then objective.filter_blocked = true end - + objective.swap_after[needs] = true needs.swap_before[objective] = true end @@ -1351,7 +1351,7 @@ function QuestHelper:IgnoreObjective(objective) else objective.user_ignore = true end - + --self:ForceRouteUpdate() end @@ -1371,13 +1371,13 @@ end local function CalcObjectivePriority(obj) local priority = obj.priority - + for o in pairs(obj.before) do if o.watched then priority = math.min(priority, CalcObjectivePriority(o)) end end - + return priority end @@ -1387,7 +1387,7 @@ local function ApplyBlockPriority(obj, level) ApplyBlockPriority(o, level) end end - + if obj.priority < level then QuestHelper:SetObjectivePriority(obj, level) end end @@ -1409,13 +1409,13 @@ function QuestHelper:SetObjectiveProgress(objective, user, have, need) list = self:CreateTable("objective.progress") objective.progress = list end - + local user_progress = list[user] if not user_progress then user_progress = self:CreateTable("objective.progress[user]") list[user] = user_progress end - + local pct = 0 local a, b = tonumber(have), tonumber(need) if a and b then @@ -1427,14 +1427,14 @@ function QuestHelper:SetObjectiveProgress(objective, user, have, need) elseif a == b then pct = 1 end - + user_progress[1], user_progress[2], user_progress[3] = have, need, pct else if objective.progress then if objective.progress[user] then self:ReleaseTable(objective.progress[user]) objective.progress[user] = nil - + if not next(objective.progress, nil) then self:ReleaseTable(objective.progress) objective.progress = nil diff --git a/QuestHelper/pathfinding.lua b/QuestHelper/pathfinding.lua index bd9604d..a0d4c2f 100644 --- a/QuestHelper/pathfinding.lua +++ b/QuestHelper/pathfinding.lua @@ -16,11 +16,11 @@ QuestHelper_Loadtime["pathfinding.lua"] = GetTime() -- So make one general setting for the 10 seconds plus 5 for the world to load -- local porttime = 15 - + QueryQuestsCompleted(); local dependancy_quest_list = GetQuestsCompleted() -local static_alliance_landings = +local static_alliance_landings = { {471, 0.476, 0.598, "Exodar via portal"}, -- Exodar {381, 0.435, 0.787, "Darnassus via portal"}, -- Darnassus @@ -28,7 +28,7 @@ local static_alliance_landings = {341, 0.255, 0.084, "Ironforge via portal"}, -- Ironforge {141, 0.660, 0.490, "Theramore via portal"}, -- Theramore, Dustwallow Marsh } - + local static_horde_landings = { {321, 0.483, 0.645, "Orgrimmar via portal"}, -- Orgrimmar @@ -37,7 +37,7 @@ local static_horde_landings = {480, 0.583, 0.192, "Silvermoon City via portal"}, -- Silvermoon City {38, 0.498, 0.558, "Stonard via portal"}, -- Stonard, Swamp of Sorrows } - + local static_shared_landings = { {504, 0.559, 0.468, "Dalaran via portal"}, -- Dalaran @@ -55,7 +55,7 @@ end -- More storage - -- Contingent on player's faction controlling the zone + -- Contingent on player's faction controlling the zone -- {{501, 0.491, 0.153}, {504, 0.268, 0.447}, 5, true}, -- Wingergrasp Keep --> Dalaran -- {{708, 0.472, 0.519}, ORGRIMMAR_CATPORTAL_IN, 60, true}, -- Tol Barad --> Orgrimmar (If Horde Controlled) -- {{708, 0.472, 0.519}, STORMWIND_CATPORTAL_IN, 60, true}, -- Tol Barad --> Stormwind (If Alliance Controlled) @@ -67,7 +67,7 @@ local BLASTED_LANDS_PORTAL_IN = {19, 0.539, 0.461, "Blasted Lands via portal"} local ORGRIMMAR_CATPORTAL_IN = {321, 0.500, 0.377, "Orgrimmar via portal"} -- local STORMWIND_CATPORTAL_IN -local static_horde_routes = +local static_horde_routes = { -- Portals {{321, 0.471, 0.618}, BLASTED_LANDS_PORTAL_IN, 60, true, level_limit = 58}, -- Orgrimmar --> Dark Portal @@ -81,10 +81,10 @@ local static_horde_routes = {{465, 0.886, 0.477}, {321, 0.483, 0.645}, 60, true}, -- Hellfire Peninsula --> Orgrimmar {{700, 0.736, 0.535}, ORGRIMMAR_CATPORTAL_IN, 60, true}, -- Twilight Highlands --> Orgrimmar - + {{321, 0.475, 0.392}, {709, 0.560, 0.799}, 60, false, level_limit = 85}, -- Orgrimmar <--> Tol Barad Peninsula - + -- Okay, I give. Since I haven't actually been through these portals, I don't really have a frame -- of reference, but from everything I can see, there are a jumble of dependancies woven throughout -- the quest chains that open the connections from Cataclysm to and from Orgrimmar, and likewise @@ -93,21 +93,21 @@ local static_horde_routes = -- of these portals, you're going to have started the quest chain, which can't happen before the -- listed level. Once I've run these myself and understand just what's going on, then I can start -- tying them to the proper quest-completion dependancy. - + -- From what I understand, at some point a portal from Orgrimmar to the zone opens in the EarthShrine -- area in Orgrimmar. When exactly is unclear. Some zones, but not all, have a return portal. -- This, too, is unclear. - + -- Orgrimmar --> Temple of Earth (Aqua) -- Level limit because the quest to open requires level 82. {{640, 0.509, 0.531}, ORGRIMMAR_CATPORTAL_IN, 60, true}, -- Temple of Earth (Aqua) --> Orgrimmar {{321, 0.508, 0.363}, {640, 0.506, 0.529}, 60, true, level_limit = 82}, -- Orgrimmar --> Deepholm -- Level limit because the quest to open requires level 82. - + {{321, 0.511, 0.383}, {606, 0.635, 0.234}, 60, true, level_limit = 80}, -- Orgrimmar --> Mount Hyjal -- Level limit because the quest to open requires level 80. - + {{321, 0.502, 0.394}, {700, 0.736, 0.534}, 60, true, level_limit = 84}, -- Orgrimmar --> Twilight Highlands -- Level limit because the quest to open requires level 84. @@ -126,7 +126,7 @@ local static_horde_routes = {{20, 0.619, 0.591}, {37, 0.374, 0.509}, 210}, -- Tirisfal Glades <--> Grom'gol Base Camp, Northern Stranglethorn {{20, 0.590, 0.590}, {491, 0.777, 0.282}, 210}, -- Tirisfal Glades <--> Vengeance Landing - + -- Ships {{700, 0.735, 0.528}, {700, 0.767, 0.152}, 210}, -- Dragonmaw Port, Twilight Highlands <--> Krazzworks, Twilight Highlands -- QuestHelper does not appear to like transitions from within the same zone. Gonna have to figure this out. @@ -134,14 +134,14 @@ local static_horde_routes = } -local static_alliance_routes = +local static_alliance_routes = { -- Portals {{381,0.440,0.782}, BLASTED_LANDS_PORTAL_IN, 60, true, level_limit = 58}, -- Darnassus --> Dark Portal {{471,0.482,0.630}, BLASTED_LANDS_PORTAL_IN, 60, true, level_limit = 58}, -- Exodar --> Dark Portal {{341,0.273,0.070}, BLASTED_LANDS_PORTAL_IN, 5, true, level_limit = 58}, -- Ironforge --> Dark Portal {{301,0.490,0.874}, BLASTED_LANDS_PORTAL_IN, 5, true, level_limit = 58}, -- Stormwind --> Dark Portal - + {{465, 0.886, 0.528}, {301, 0.496, 0.865}, 60, true}, -- Hellfire Peninsula --> Stormwind {{381, 0.442, 0.788}, {471, 0.476, 0.598}, 5, true}, -- Darnassus --> Exodar {{471, 0.476, 0.619}, {381, 0.435, 0.787}, 5, true}, -- Exodar --> Darnassus @@ -151,7 +151,7 @@ local static_alliance_routes = {{301, 0.734, 0.195}, {640, 0.487, 0.536}, 60, true, level_limit = 82}, -- Stormwind --> Temple of Earth (Amber) -- Level limit because the quest to open requires level 82. {{640, 0.486, 0.537}, {301, 0.745, 0.183}, 60, true}, -- Temple of Earth (Amber) --> Stormwind - + -- Stormwind <--> Deepholm -- Stormwind <--> Mount Hyjal -- Stormwind <--> Twilight Highlands @@ -175,27 +175,27 @@ local static_alliance_routes = {{684, 0.42, 0.36}, {41, 0.52, 0.89}, 86400}, -- Gilneas Zone <--> Teldrassil. Exists solely to fix some pathing crashes. 24-hour boat ride :D (This will be deleted later, when we can create the "official" path.) } -local static_shared_routes = +local static_shared_routes = { -- Portals {{504, 0.268, 0.447}, {504, 0.240, 0.394}, 5}, -- Dalaran (Violet Citadel) <--> Dalaran (Purple Parlor) - + {{504, 0.559, 0.468}, {510, 0.158, 0.428}, 5}, -- Dalaran <--> Crystalsong Forest --{{504, 0.559, 0.468}, {510, 0.158, 0.428}, 5, false, level_limit = 68}, -- Dalaran <--> Crystalsong Forest {{41, 0.551, 0.885}, {381, 0.369, 0.584}, 5}, -- Rut'Theran Village, Teldrassil <--> Darnassus - + {{19, 0.550, 0.541}, {465, 0.898, 0.502}, 60}, -- Blasted Lands <--> Hellfire Peninsula (Dark Portal) {{504, 0.255, 0.514}, {161, 0.652, 0.498}, 60, true}, -- Dalaran --> Caverns of Time {{481, 0.486, 0.420}, {499, 0.482, 0.345}, 60, true}, -- Shattrath --> Isle of Quel'Danas - + {{481, 0.747, 0.316}, {161, 0.652, 0.498}, 60, true}, -- Shattrath --> Caverns of Time -- Requires Revered with Keepers of Time {{640, 0.493, 0.504}, {640, 0.571, 0.135}, 5, false, level_limit = 81}, -- Temple of Earth <--> Therazane's Throne -- Requires Honored with Therazane and dependant on quest #26709 - + -- Ships {{488, 0.497, 0.784}, {491, 0.234, 0.578}, 210}, -- Moa'ki <--> Kamagua {{488, 0.479, 0.788}, {486, 0.789, 0.537}, 210}, -- Moa'ki <--> Unu'pe @@ -253,40 +253,40 @@ local static_shared_routes = {{144, 0.500, 0.500}, {73, 0.416, 0.179}, 5}, -- Ulduar, zone-in link is incorrect {{155, 0.426, 0.203}, {71, 0.548, 0.899}, 5}, -- Forge of Souls {{157, 0.410, 0.801}, {71, 0.547, 0.916}, 5}, -- Pit of Saron - + -- Wrath in-zone links, all currently incorrect -- UK {{80, 0.500, 0.500}, {82, 0.500, 0.500}, 5}, {{80, 0.500, 0.500}, {84, 0.500, 0.500}, 5}, - + -- AN {{88, 0.500, 0.500}, {90, 0.500, 0.500}, 5}, {{88, 0.500, 0.500}, {92, 0.500, 0.500}, 5}, - + -- Drak {{96, 0.500, 0.500}, {98, 0.500, 0.500}, 5}, - + -- HoL {{106, 0.500, 0.500}, {108, 0.500, 0.500}, 5}, - + -- Oculus {{110, 0.500, 0.500}, {112, 0.500, 0.500}, 5}, {{110, 0.500, 0.500}, {114, 0.500, 0.500}, 5}, {{110, 0.500, 0.500}, {116, 0.500, 0.500}, 5}, - + -- CoT {{120, 0.500, 0.500}, {118, 0.500, 0.500}, 5}, - + -- UP {{122, 0.500, 0.500}, {124, 0.500, 0.500}, 5}, - + -- Naxx {{128, 0.500, 0.500}, {130, 0.500, 0.500}, 5}, {{128, 0.500, 0.500}, {132, 0.500, 0.500}, 5}, {{128, 0.500, 0.500}, {134, 0.500, 0.500}, 5}, {{128, 0.500, 0.500}, {136, 0.500, 0.500}, 5}, {{128, 0.500, 0.500}, {138, 0.500, 0.500}, 5}, - + -- Ulduar {{144, 0.500, 0.500}, {146, 0.500, 0.500}, 5}, {{144, 0.500, 0.500}, {148, 0.500, 0.500}, 5}, @@ -300,11 +300,11 @@ local dark_portal_route = {{19, 0.550, 0.541}, {465, 0.898, 0.502}, 60} -- Waygate local ridingLevel = (select(4,GetAchievementInfo(892)) and 300) or (select(4,GetAchievementInfo(890)) and 225) or (select(4,GetAchievementInfo(889)) and 150) or (select(4,GetAchievementInfo(891)) and 75) or 0 -- this is thanks to Maldivia, who is a fucking genius -local has_fmsl = not not GetSpellInfo(GetSpellInfo(90267)) -if ridingLevel >= 225 and has_fmsl then +local has_fmsl = not not GetSpellInfo(GetSpellInfo(90267)) +if ridingLevel >= 225 and has_fmsl then table.insert(static_shared_routes, {{201, 0.505, 0.078}, {493, 0.403, 0.830}, 60, false, level_limit = 77}) -- Un'Goro Crater <--> Sholazar Basin -- Dependant on completion of quest #12613 -end +end -- Cataclysm Quest-dependant static routes -- STILL WORKING ON THESE. See Notes under Static_Horde. @@ -322,21 +322,21 @@ local static_zone_transitions = -- Eastern Kingdoms -- Kalimdor - + --Outland - + --Northrend {486, 493, 0.527, 0.322}, -- Borean Tundra <--> Scholazar Basin - + --Cataclysm zones - + -- Work {4, 321, 0.117, 0.936}, -- Durotar <--> Orgrimmar (Front) {4, 321, 0.366, 0.253}, -- Durotar <--> Orgrimmar (Side) {181, 321, 0.792, 0.017}, -- Azshara <--> Orgrimmar (Back) {772, 261, 0.687, 0.2}, -- Ahn'Qiraj <--> Silithus {37, 673, 0.50, 0.61}, -- Northern Stranglethorn <--> Cape of Stranglethorn - + --{38, 168, 0, 0}, -- Stranglethorn World Map Wonkiness {43, 11, 0.687, 0.872}, -- Ashenvale <--> Northern Barrens @@ -401,7 +401,7 @@ local static_zone_transitions = {24, 26, 0.899, 0.253}, -- Hillsbrad Foothills <--> The Hinterlands {40, 700, 0.80, 0.47}, -- Wetlands <--> Twilight Highlands {35, 40, 0.252, 0}, -- Loch Modan <--> Wetlands - + -- Outland {477, 481, 0.783, 0.545}, -- Nagrand <--> Shattrath City -- this is aldor-only {481, 478, 0.782, 0.492}, -- Shattrath City <--> Terokkar Forest @@ -415,10 +415,10 @@ local static_zone_transitions = {477, 467, 0.754, 0.331}, -- Nagrand <--> Zangarmarsh {473, 478, 0.208, 0.271}, -- Shadowmoon Valley <--> Terokkar Forest {478, 467, 0.341, 0.098}, -- Terokkar Forest <--> Zangarmarsh - + -- Northrend {486, 488, 0.967, 0.359}, -- Borean Tundra <--> Dragonblight - {501, 493, 0.208, 0.191}, -- Wintergrasp <--> Sholazar + {501, 493, 0.208, 0.191}, -- Wintergrasp <--> Sholazar {488, 501, 0.250, 0.410}, -- Dragonblight <--> Wintergrasp {488, 492, 0.359, 0.155}, -- Dragonblight <--> Icecrown {488, 510, 0.612, 0.142}, -- Dragonblight <--> Crystalsong @@ -451,44 +451,11 @@ end function load_graph_links() local function convert_coordinate(coord) QuestHelper: Assert(coord[1] and coord[2] and coord[3]) - --[==[ - -- I hate Blizzard... They can't make up their mind weather we are on TwilightHighlands or TwilightHiglands_terrain1, but we only seem to be on one or the other. - if coord[1] == 177 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 184 - elseif coord[1] == 184 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 177 - end - - -- I hate Blizzard... They can't make up their mind weather we are on Hyjal or Hyjal_terrain1, but we only seem to be on one or the other. - if coord[1] == 198 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 185 - elseif coord[1] == 185 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 198 - end - - -- I hate Blizzard... They can't make up their mind weather we are on Uldum or Uldum_terrain1, but we only seem to be on one or the other. - if coord[1] == 164 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 210 - elseif coord[1] == 210 and not QuestHelper_ZoneLookup[coord[1]] then - coord[1] = 164 - end - - -- I hate Blizzard... They can't make up their mind whether we are on LostIsles, LostIsles_terrain1 or LostIsles_terrain2, but we only seem to be on one. - - -- Create a lookup table. - local converter = {} - converter[181] = function() return convertLostIsles(181, 208, 209) end - converter[208] = function() return convertLostIsles(208, 181, 209) end - converter[209] = function() return convertLostIsles(209, 181, 208) end - - -- Use the lookup table to get the real coordinate. - if converter[coord[1]] then coord[1] = converter[coord[1]]() end - ]==] local QHZL = QuestHelper_ZoneLookup - QuestHelper: Assert(QuestHelper_ZoneLookup[coord[1]], string.format("Coord[1] = %d", coord[1])) - local c, x, y = QuestHelper.Astrolabe:GetAbsoluteContinentPosition(QuestHelper_ZoneLookup[coord[1]][1], QuestHelper_ZoneLookup[coord[1]][2], coord[2], coord[3]) +-- QuestHelper: Assert(QuestHelper_ZoneLookup[coord[1]], string.format("Coord[1] = %d", coord[1])) +-- local c, x, y = QuestHelper.Astrolabe:GetAbsoluteContinentPosition(QuestHelper_ZoneLookup[coord[1]][1], QuestHelper_ZoneLookup[coord[1]][2], coord[2], coord[3]) QuestHelper: Assert(c) - return {x = x, y = y, p = coord[1], c = c} + return {x = coord[2], y = coord[3], m = coord[1], f = coord[4] or 0} end local function do_routes(routes) @@ -499,16 +466,16 @@ QuestHelper:Assert(v[2], tostring(k) .. " is the key, v[2]. v[1] is " .. tostrin local src = convert_coordinate(v[1]) local dst = convert_coordinate(v[2]) QuestHelper: Assert(src.x and dst.x) - src.map_desc = {QHFormat("WAYPOINT_REASON", QuestHelper_NameLookup[v[2][1]])} - dst.map_desc = {QHFormat("WAYPOINT_REASON", QuestHelper_NameLookup[v[1][1]])} - + src.map_desc = {QHFormat("WAYPOINT_REASON", "SOURCE")} --QuestHelper_NameLookup[v[2][1]])} + dst.map_desc = {QHFormat("WAYPOINT_REASON", "DEST")} --QuestHelper_NameLookup[v[1][1]])} + local rev_cost = v[3] if v[4] then rev_cost = nil end QH_Graph_Plane_Makelink("static_route", src, dst, v[3], rev_cost) -- this couldn't possibly fail end end end - + -- Generating landing_db for potential use in adding Mage portals and Hearthstone to routing local faction_db local landing_db @@ -519,11 +486,11 @@ QuestHelper:Assert(v[2], tostring(k) .. " is the key, v[2]. v[1] is " .. tostrin faction_db = static_horde_routes landing_db = static_horde_landings end - + -- Not adding landing_db or static_shared_landings here because it depend on implimentation do_routes(faction_db) do_routes(static_shared_routes) - + for k, v in ipairs(static_zone_transitions) do QuestHelper:Assert(v[1], tostring(k) .. " is the key, v[1]-2.") QuestHelper:Assert(v[3], tostring(k) .. " is the key, v[3]-2.") @@ -531,18 +498,18 @@ QuestHelper:Assert(v[4], tostring(k) .. " is the key, v[4]-2.") local src = convert_coordinate({v[1], v[3], v[4]}) local dst = convert_coordinate({v[1], v[3], v[4]}) dst.p = v[2] - src.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", QuestHelper_NameLookup[v[2]]))} - dst.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", QuestHelper_NameLookup[v[1]]))} + src.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", "BORDER SOURCE"))} --QuestHelper_NameLookup[v[2]]))} + dst.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", "BORDER DEST"))} --QuestHelper_NameLookup[v[1]]))} QH_Graph_Plane_Makelink("static_transition", src, dst, 0, 0) end - + do QuestHelper:Assert(dark_portal_route[1], "DPR1") QuestHelper:Assert(dark_portal_route[2], "DPR2") local src = convert_coordinate(dark_portal_route[1]) local dst = convert_coordinate(dark_portal_route[2]) - src.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", QuestHelper_NameLookup[dark_portal_route[2]]))} - dst.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", QuestHelper_NameLookup[dark_portal_route[1]]))} + src.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", "DKPTL SOURCE"))} --QuestHelper_NameLookup[dark_portal_route[2]]))} + dst.map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("ZONE_BORDER_SIMPLE", "DKPTL DEST"))} --QuestHelper_NameLookup[dark_portal_route[1]]))} QH_Graph_Plane_Makelink("dark_portal", src, dst, 15, 15) end end diff --git a/QuestHelper/radar.lua b/QuestHelper/radar.lua index ec51012..782740f 100644 --- a/QuestHelper/radar.lua +++ b/QuestHelper/radar.lua @@ -33,15 +33,15 @@ QH_OnUpdate(function() return end quieted = false - + if not rc then rc = LibStub("LibRangeCheck-2.0") end - + if tick <= GetTime() then tick = tick + 1 if tick < GetTime() then tick = GetTime() end - + local targ = UnitGUID("target") if targ ~= anchor or UnitIsDead("target") then for _, v in pairs(map) do QuestHelper:ReleaseTable(v) end @@ -52,25 +52,25 @@ QH_OnUpdate(function() end anchor = targ end - + local minRange, maxRange = rc:GetRange('target') - + if minRange then if not maxRange then maxRange = 120 end - + minRange = math.max(0, minRange - 1) maxRange = maxRange + 1 - + local mnr, mxr = minRange * minRange, maxRange * maxRange local px, py = QuestHelper.routing_ax, QuestHelper.routing_ay - + -- first we blur local newmap = QuestHelper:CreateTable("radar") for x, d in pairs(map) do if not newmap[x - grid] then newmap[x - grid] = QuestHelper:CreateTable("radar") end if not newmap[x] then newmap[x] = QuestHelper:CreateTable("radar") end if not newmap[x + grid] then newmap[x + grid] = QuestHelper:CreateTable("radar") end - + for y, v in pairs(d) do newmap[x - grid][y - grid] = (newmap[x - grid][y - grid] or 0) + v newmap[x - grid][y] = (newmap[x - grid][y] or 0) + v * 2 @@ -82,13 +82,13 @@ QH_OnUpdate(function() newmap[x + grid][y] = (newmap[x + grid][y] or 0) + v * 2 newmap[x + grid][y + grid] = (newmap[x + grid][y + grid] or 0) + v end - + QuestHelper:ReleaseTable(d) end QuestHelper:ReleaseTable(map) map = newmap - - + + -- then we crop local highest = 0 local newmap = QuestHelper:CreateTable("radar") @@ -107,7 +107,7 @@ QH_OnUpdate(function() something = true end end - + if something then newmap[x] = newk end @@ -115,7 +115,7 @@ QH_OnUpdate(function() end QuestHelper:ReleaseTable(map) map = newmap - + -- then we normalize if highest > 0 then highest = 1 / highest -- I don't know if mult is faster in lua or not, but it often is @@ -125,7 +125,7 @@ QH_OnUpdate(function() end end end - + -- then we add -- probably a more efficient way to do this px, py = math.floor(px / grid + 0.5) * grid, math.floor(py / grid + 0.5) * grid @@ -148,7 +148,7 @@ QH_OnUpdate(function() end end end - + -- then we post local widgetofs = 1 for x, d in pairs(map) do @@ -162,7 +162,7 @@ QH_OnUpdate(function() widg[1]:SetHeight(lheight) end widgetofs = widgetofs + 1 - + widg[1]:SetTexture(0, 1, 0, math.min(1, v * 1.2)) widg[1]:Show() widg[2] = x @@ -170,25 +170,25 @@ QH_OnUpdate(function() end end end - + for rem = widgetofs, #widgets do widgets[rem][1]:Hide() widgets[rem][3] = nil end end end - + -- here we replace the widgets - + local rotatey = (GetCVar("rotateMinimap") == "0") and 0 or GetPlayerFacing() rotatey = rotatey * 180 / 3.14159 - + -- WILL FAIL HERE. local mapdiam = QuestHelper.Astrolabe:GetMapDiameter() local minimap = QuestHelper.Astrolabe:GetMinimapObject() local mapwid, maphei = minimap:GetWidth(), minimap:GetHeight() - + local xds, yds = mapwid / mapdiam, maphei / mapdiam - + local nwidth, nheight = xds * grid, yds * grid if nwidth ~= lwidth or nheight ~= lheight then for _, widg in pairs(widgets) do @@ -197,18 +197,18 @@ QH_OnUpdate(function() end end lwidth, lheight = nwidth, nheight - + local xdx, xdy, ydx, ydy = cos(rotatey), -sin(rotatey), -sin(rotatey), -cos(rotatey) -- this will be wrong, but I'll figure it out xdx, ydx = xdx * xds, ydx * xds xdy, ydy = xdy * yds, ydy * yds - + local px, py = QuestHelper.routing_ax, QuestHelper.routing_ay - + for _, v in pairs(widgets) do if not v[3] then break end - + local dx, dy = v[2] - px, v[3] - py - + v[1]:SetPoint("CENTER", Minimap, "CENTER", dx * xdx + dy * ydx, dx * xdy + dy * ydy) --print("placing", dx * xdx + dy * ydx, dx * xdy + dy * ydy) end diff --git a/QuestHelper/routing.lua b/QuestHelper/routing.lua index a42f0bf..5426bfb 100644 --- a/QuestHelper/routing.lua +++ b/QuestHelper/routing.lua @@ -17,13 +17,13 @@ local work_done = 0 local function CalcObjectivePriority(obj) local priority = obj.priority - + for o in pairs(obj.before) do if o.watched then priority = math.min(priority, CalcObjectivePriority(o)) end end - + obj.real_priority = priority return priority end @@ -34,9 +34,9 @@ Routing.Route = Route -- Make it available as a member -- This should pass on all routes. If it does not, *things need to be fixed*. No, commenting tests out is not an adequate response - this *must* pass. Eventually this will get rolled into the unsucky Route class. function Route:sanity() - + local assert = assert - + if QuestHelper.Error then assert = function(a, b) if not a then @@ -45,9 +45,9 @@ function Route:sanity() end end end - + local l = 0 - + --QuestHelper:TextOut(QuestHelper:StringizeTable(self)) for i = 0,#self-1 do --QuestHelper:TextOut(tostring(i)) @@ -56,24 +56,24 @@ function Route:sanity() --[[ assert(self[i].len) ]] l = l + self[i].len end - + --QuestHelper:TextOut("sd: "..l.." rd: "..self.distance) --[[ assert(math.abs(l-self.distance) < 0.0001, string.format("compare %f vs %f", l, self.distance)) ]] - + for i, info in ipairs(self) do --[[ assert(self.index[info.obj] == i) ]] --[[ assert(info.pos) ]] end - + for obj, i in pairs(self.index) do --[[ assert(self[i].obj == obj) ]] end - + for i = 1, #self-1 do local l = QuestHelper:ComputeTravelTime(self[i].pos, self[i+1].pos, true) --[[ assert(math.abs(l-self[i].len) < 0.0001, "Compare at "..i..": "..l.." vs "..self[i].len) ]] end - + return true end @@ -85,49 +85,49 @@ function Route:findObjectiveRange(obj, passes) for i = 1, #self do table.insert(lines, string.format("%d %d %d --- %d %d %d (vs %s, %d)", obj.real_priority > self[i].obj.real_priority and 1 or 0, obj.after[self[i].obj] and 1 or 0, self[i].obj.before[obj] and 1 or 0, obj.real_priority < self[i].obj.real_priority and 1 or 0, obj.before[self[i].obj] and 1 or 0, self[i].obj.after[obj] and 1 or 0, self[i].obj.obj, self[i].obj.real_priority)) end]] - + local mn = #self while mn >= 1 do if obj.real_priority > self[mn].obj.real_priority or obj.after[self[mn].obj] or self[mn].obj.before[obj] then break end mn = mn - 1 end - + mn = mn + 1 -- we went too far, actually - + local mx = 1 while mx < #self + 1 do if obj.real_priority < self[mx].obj.real_priority or obj.before[self[mx].obj] or self[mx].obj.after[obj] then break end mx = mx + 1 end - + --table.insert(lines, string.format("temp results is %d %d", mn, mx)) - + if mx < mn then -- well, technically, there's no place we can put this. So we guess wildly. Eventually it'll sanify itself. We hope. local mid = math.ceil((mx + mn) / 2) mx = mid mn = mid end - + --table.insert(lines, string.format("overall: %d %d", mn, mx)) - + --[[ - if passes and passes > 90 then + if passes and passes > 90 then for k, v in pairs(lines) do QuestHelper:TextOut(v) end QuestHelper:TextOut(string.format("overall: %d %d", mn, mx)) end ]] - + --[[ local omn, omx = self:OldFindObjectiveRange(obj) - + if mn ~= omn or mx ~= omx then for k, v in pairs(lines) do QuestHelper:TextOut(v) end QuestHelper:TextOut(string.format("overall: %d %d vs %d %d", mn, mx, omn, omx)) lolcrash = (lolcrash or 0) + 1 end]] - + return mn, mx, lines - + end function Route:addObjectiveFast(obj) @@ -136,9 +136,9 @@ function Route:addObjectiveFast(obj) local len = #self local info = QuestHelper:CreateTable() --[[ assert(not indexes[obj]) ]] - + info.obj = obj - + if len == 0 then local d self[1] = info @@ -148,14 +148,14 @@ function Route:addObjectiveFast(obj) self.distance = d return 1 end - + local player_pos = QuestHelper.pos local pos = obj.location local c, x, y = pos[1].c, pos[3], pos[4] - + local mn, mx = self:findObjectiveRange(obj) local index, distsqr - + for i = mn, math.min(mx, len) do local p = self[i].pos if c == p[1].c then @@ -166,28 +166,28 @@ function Route:addObjectiveFast(obj) end end end - + if not index then -- No nodes with the same continent already. -- If the same continent as the player, add to start of list, otherwise add to end of the list. index = c == player_pos[1].c and mx or mx end - + -- The next question, do I insert at that point, or do I insert after it? if index ~= mx and index <= len then local p1 = self[index].pos - + if p1[1].c == c then local p0 - + if index == 1 then p0 = player_pos else p0 = self[index-1].pos end - + local oldstart, newstart - + if p0[1].c == c then local u, v = p0[3]-x, p0[4]-y newstart = math.sqrt(u*u+v*v) @@ -197,12 +197,12 @@ function Route:addObjectiveFast(obj) newstart = 0 oldstart = 0 end - + local p2 if index ~= len then p2 = self[index+1].pos end - + local oldend, newend if p2 and p2[1].c == c then local u, v = p2[3]-x, p2[4]-y @@ -213,16 +213,16 @@ function Route:addObjectiveFast(obj) newend = 0 oldend = 0 end - + if oldstart+newend < newstart+oldend then index = index + 1 end - + end end - + QH_Timeslice_Yield() -- The above checks don't require much effort. - + if index > len then local previnfo = self[index-1] --[[ assert(previnfo) ]] @@ -234,43 +234,43 @@ function Route:addObjectiveFast(obj) self.distance = self.distance + d else local d1, d2 - + local previnfo = self[index-1] d1, d2, info.pos = obj:TravelTime2(previnfo.pos, self[index].pos, previnfo.no_cache) - + info.len = d2 self.distance = self.distance + (d1 - previnfo.len + d2) previnfo.len = d1 - + QH_Timeslice_Yield() end - + -- Finally, insert the objective. table.insert(self, index, info) indexes[obj] = index - + -- Fix indexes of shifted elements. for i = index+1,len+1 do local obj = self[i].obj --[[ assert(indexes[obj] == i-1) ]] indexes[obj] = i end - + --[[ assert(self:sanity()) ]] - + return index end function Route:addObjectiveBest(obj, old_index, old_distance) --[[ assert(self:sanity()) ]] - + local indexes = self.index local len = #self local info = QuestHelper:CreateTable() --[[ assert(not indexes[obj]) ]] - + info.obj = obj - + if len == 0 then indexes[obj] = 1 self.distance, info.pos = obj:TravelTime(self[0].pos, true) @@ -279,18 +279,18 @@ function Route:addObjectiveBest(obj, old_index, old_distance) self[1] = info return 1 end - + local sanityfixed = nil -- If we've done something to improve the sanity of the overall path, i.e. force the path into a situation where it's no longer trying to turn in quests before the quest has been completed, then we definitely want to accept this path overall. Before, this wasn't a problem, since this function was so unstable that it would randomly change the path anyway, and it doesn't *break* things once they're fixed. Now that we have a check that this function actually *improves* the path, we need a slightly more complicated definition of "improve". Ideally, that shouldn't be necessary, but for now it is (until, at least, this function actually puts things in the best location, and that will have to wait until the get-optimal-path functions actually get optimal paths.) - + local best_index, best_delta, best_d1, best_d2, best_p local no_cache, prev_pos, prev_len local mn, mx = self:findObjectiveRange(obj) - + if old_index and mn <= old_index and old_index <= mx then -- We're trying to re-evaluate it, and it could remain in the same place. -- So that place is our starting best known place. best_index, best_delta = old_index, old_distance - self.distance - + if best_delta < 0 then -- Somehow, removing the objective actually made the route worse... -- Just re-figure things from scratch. @@ -299,22 +299,22 @@ function Route:addObjectiveBest(obj, old_index, old_distance) best_index, best_delta = nil, nil end end - + local pinfo = self[mn-1] no_cache, prev_pos, prev_len = pinfo.no_cache, pinfo.pos, pinfo.len - + for i = mn, math.min(mx, len) do --[[ assert(prev_pos == self[i-1].pos) ]] - + local info = self[i] local pos = info.pos - + local d1, d2, p = obj:TravelTime2(prev_pos, pos, no_cache) - + QH_Timeslice_Yield() - + local delta = d1 + d2 - prev_len - + if not best_index or ((delta + improve_margin) < best_delta) or ((i == best_index) and not best_d1) then -- Best so far is: -- * First item we reach @@ -324,19 +324,19 @@ function Route:addObjectiveBest(obj, old_index, old_distance) -- that's how. Save the specifics, 'cause we didn't compute them when setting up. best_index, best_delta, best_d1, best_d2, best_p = i, delta, d1, d2, p end - + prev_pos = pos prev_len = info.len no_cache = false end - + if mx > len then --[[ assert(mx == len+1) ]] --[[ assert(prev_pos == self[len].pos) ]] local delta, p = obj:TravelTime(prev_pos, no_cache) - + QH_Timeslice_Yield() - + if not best_index or ((delta + improve_margin) < best_delta) or ((mx == best_index) and not best_d1) then info.pos = p info.len = 0 @@ -344,57 +344,57 @@ function Route:addObjectiveBest(obj, old_index, old_distance) self.distance = self.distance + delta table.insert(self, info) indexes[obj] = mx - + --[[ assert(self:sanity()) ]] - + return mx end end info.pos = best_p info.len = best_d2 - + local pinfo = self[best_index-1] self.distance = self.distance + (best_d1 - pinfo.len + best_d2) pinfo.len = best_d1 - + table.insert(self, best_index, info) - + -- --[[ QuestHelper:Assert(math.abs(QuestHelper:ComputeTravelTime(self[best_index-1].pos, self[best_index].pos) - self[best_index-1].len) < 0.0001, "aaaaargh") ]] --[[ -- I don't think this is necessary now that TravelTime2 explicitly does this internally, but I'm keeping it anyway. self.distance = self.distance - self[best_index-1].len self[best_index-1].len = QuestHelper:ComputeTravelTime(self[best_index-1].pos, self[best_index].pos, true) self.distance = self.distance + self[best_index-1].len ]] - + indexes[obj] = best_index - + for i = best_index+1,len+1 do --[[ assert(indexes[self[i].obj] == i-1) ]] indexes[self[i].obj] = i end - + if not old_index or (mn > old_index or old_index > mx) and mn <= best_index and best_index <= mx then -- if we didn't have an old index, or our old index was out of bounds and our best index is in bounds, then we've done something Majorly Good and we should be using this path even if the old one was faster sanityfixed = 1 end - + --[[ assert(self:sanity()) ]] - + return best_index, sanityfixed end function Route:removeObjective(obj) --[[ assert(self:sanity()) ]] - + local indexes = self.index local index = indexes[obj] local old_distance = self.distance - + --[[ assert(index) ]] local info = self[index] --[[ assert(info.obj == obj) ]] - + --[[ Removing end item: subtract last distance, nothing to recalculate Removing other item: recalculate location of next objective, between prior position and objective after next @@ -408,9 +408,9 @@ function Route:removeObjective(obj) local info1 = self[index+1] local info2 = self[index+2] local no_cache = (index == 1) - + local d1, d2 - + if info2 then d1, d2, info1.pos = info1.obj:TravelTime2(pinfo.pos, info2.pos, no_cache) QH_Timeslice_Yield() @@ -421,24 +421,24 @@ function Route:removeObjective(obj) QH_Timeslice_Yield() self.distance = self.distance - pinfo.len - info.len + d1 end - + pinfo.len = d1 end - + QuestHelper:ReleaseTable(info) indexes[obj] = nil table.remove(self, index) - + for i = index,#self do -- Fix indexes of shifted elements. local obj = self[i].obj --[[ assert(indexes[obj] == i+1) ]] indexes[obj] = i end - + --[[ assert(self:sanity()) ]] -- --[[ assert(self.distance <= old_distance) ]] - + return index end @@ -448,13 +448,13 @@ local seen = {} function Route:breed(route_map) local indexes = self.index local len = #self - + local info local r - + local prev_pos = QuestHelper.pos --[[ assert(self[0].pos == prev_pos) ]] - + -- Pick which objective goes first, selecting from first objective of each route, -- and scaling by the route's fitness and distance from player, with a random adjustment factor. -- While we're at it, record some data about the fitness of adjacent objectives @@ -463,20 +463,20 @@ function Route:breed(route_map) local fit = route.fitness local pos = route[1].pos local w - + if prev_pos[1].c == pos[1].c then local u, v = prev_pos[3]-pos[3], prev_pos[4]-pos[4] w = math.sqrt(u*u+v*v) else w = 500 end - + w = fit * math.random() / w - + if not info or w > r then info, r = route[1], w end - + for i = 1,len do local obj = route[i].obj local tbl = links[obj] @@ -484,13 +484,13 @@ function Route:breed(route_map) tbl = QuestHelper:CreateTable() links[obj] = tbl end - + if i ~= 1 then local info = route[i-1] local obj2 = info.obj tbl[info] = (tbl[info] or 0) + fit end - + if i ~= len then local info = route[i+1] local obj2 = info.obj @@ -499,27 +499,27 @@ function Route:breed(route_map) end end end - + QH_Timeslice_Yield() end - + -- Record info for the 'Player Position' objective, so we don't mess it up later seen[self[0].obj] = self[0].pos - + -- Record the objective that we chose to put first local obj = info.obj indexes[obj] = 1 seen[obj] = info.pos -- Save its position, because we don't want to clobber any of the info objects yet prev_pos = info.pos - + last = links[obj] links[obj] = nil - + -- Scan the rest of the places in the route, and pick objectives to go there for index = 2,len do info = nil local c = 1 - + -- Scan the list of scores from the prior objective for i, weight in pairs(last) do if links[i.obj] then @@ -532,16 +532,16 @@ function Route:breed(route_map) else w = 500 end - + w = weight * math.random() / w - + if not info or w > r then info, r = i, w end end c = c + 1 end - + -- In case we had no valid scores, scan the remaining objectives and score by distance if not info then for obj in pairs(links) do @@ -559,37 +559,37 @@ function Route:breed(route_map) -- Different continent. Assume fixed value of 5 minutes. w = 300 end - + w = math.random() / w - + if not info or w > r then local route = next(route_map) info, r = route[route.index[obj]], w end end - + --[[ assert(info) ]] end - + -- Add the selected item to the route obj = info.obj indexes[obj] = index prev_pos = info.pos seen[obj] = prev_pos --[[ assert(info.obj == obj) ]] - + -- Get the scores table for this objective, clear it out, discard the scores from the prior objective, and save these scores for next time around local link = links[obj] links[obj] = nil QuestHelper:ReleaseTable(last) last = link - + QH_Timeslice_Yield() end - + -- Clean up the last table QuestHelper:ReleaseTable(last) - + -- Now that we've got our objectives lined up, fill in the info objects with the positions we saved for obj, i in pairs(indexes) do --[[ assert(seen[obj]) ]] @@ -597,25 +597,25 @@ function Route:breed(route_map) info.obj, info.pos = obj, seen[obj] seen[obj] = nil end - + -- Now randomly randomize some of the route (aka mutation) while math.random() > 0.3 do local l = math.floor(math.random()^1.6*(len-1))+1 local i = math.random(1, len-l) local j = i+l - + -- Reverse a chunk of the route for k = 0, j-i-1 do self[i+k], self[j-k] = self[j-k], self[i+k] end end - + -- But wait, after all that some objectives might violate the rules. Make sure the route follows -- the rules. -- There's some horrifying ugly here. The "before" and "after" links are not properly updated simultaneously. This means that X can be flagged as after Y without Y being flagged as before X. Making things worse (because, oh man, things had to be made worse!) this means that X might have a lower priority than Y despite needing to happen before it. Urgh. -- Since the entire thing is internally inconsistent anyway, we're just gonna try to consistentize it. - + local valid_items = {} for k, v in ipairs(self) do valid_items[v.obj] = true @@ -632,12 +632,12 @@ function Route:breed(route_map) end end end - + -- Because priorities might have been changed in here, we next make absolutely sure we have up-to-date priorities. for k, v in ipairs(self) do CalcObjectivePriority(v.obj) end - + -- Have I mentioned I hate this codebase yet? -- Because I do. -- Just, you know. @@ -647,22 +647,22 @@ function Route:breed(route_map) local invalid_passes = 0 --local output_strings = {} while invalid do - + invalid_passes = invalid_passes + 1 - + --[[if invalid_passes >= 100 then for k, v in pairs(output_strings) do QuestHelper:TextOut(v) end end]] - + if invalid_passes >= 100 then -- ugh QuestHelper.mutation_passes_exceeded = true break end QuestHelper: Assert(invalid_passes <= 100, "Too many mutation passes needed to preserve sanity, something has gone Horribly Wrong, please report this as a bug (you will probably need to restart WoW for QH to continue working, sorry about that)") -- space is so it works in the real code - + invalid = false local i = 1 --[[for i = 1, #self do @@ -677,15 +677,15 @@ function Route:breed(route_map) if i < mn then -- In theory, 'i' shouldn't be increased here, as the next -- element will be shifted down into the current position. - + -- However, it is possible for an infinite loop to be created -- by this, with a small range of objectives constantly -- being shifted. - + -- So, I mark the route as invalid and go through it another time. -- It's probably still possible to get into an infinite loop, -- but it seems much less likely. - + table.insert(self, mn, info) table.remove(self, i) invalid = true @@ -700,7 +700,7 @@ function Route:breed(route_map) end --table.insert(output_strings, "pass done") end - + -- Now that we've chosen a route, re-calculate the cost of each leg of the route local distance = 0 local prev_info = self[0] @@ -709,36 +709,36 @@ function Route:breed(route_map) local next_pos = next_info.pos --[[ assert(prev_pos) ]] --[[ assert(next_pos) ]] - + QH_Timeslice_Yield() - + for i = 1, len-1 do local d1, d2 local pos local info = next_info next_info = self[i+1] next_pos = next_info.pos - + indexes[info.obj] = i - + d1, d2, pos = info.obj:TravelTime2(prev_pos, next_pos, prev_info.no_cache) --[[ assert(pos) ]] QH_Timeslice_Yield() - + prev_info.len = d1 info.len = d2 info.pos = pos distance = distance + d1 - + prev_info = info prev_pos = pos end - + self.distance = distance + prev_info.len - + indexes[self[len].obj] = len self[len].len = 0 - + --[[ assert(self:sanity()) ]] end @@ -753,9 +753,9 @@ function Route:pathResetEnd() for i, info in ipairs(self) do -- Try to find a new position for this objective, near where we had it originally. local p, d = nil, 0 - + local a, b, c = info[1], info[2], info[3] - + for z, pl in pairs(info.obj.p) do for i, point in ipairs(pl) do if a == point[1].c then @@ -767,18 +767,18 @@ function Route:pathResetEnd() end end end - + -- Assuming that there will still be positions on the same continents as before, i.e., locations are only added and not removed. --[[ assert(p) ]] - + info.pos = p end - + self:recalculateDistances() end function Route:recalculateDistances() - + self.distance = 0 for i = 0, #self-1 do self[i].len = QuestHelper:ComputeTravelTime(self[i].pos, self[i+1].pos) @@ -790,7 +790,7 @@ function Routing:RoutingSetup() Routing.map_walker = self.qh:CreateWorldMapWalker() Routing.add_swap = {} Routing.routes = {} - + local routes = Routing.routes local pos = QuestHelper.pos local PlayerObjective = self.qh:NewObjectiveObject() -- Pseudo-objective which reflects player's current position. Always at index 0 of each route. @@ -800,7 +800,7 @@ function Routing:RoutingSetup() PlayerObjective.icon_id = 6 -- Don't think we'll need these; just filling them in for completeness PlayerObjective.o = {pos=pos} PlayerObjective.fb = {} - + for i = 1,15 do -- Create some empty routes to use for our population. local new_rt = { index={ [PlayerObjective]=0 }, distance=0, @@ -810,44 +810,44 @@ function Routing:RoutingSetup() setmetatable(new_rt, Route) routes[new_rt] = true end - + -- All the routes are the same right now, so it doesn't matter which we're considering the best. self.best_route = next(routes) self.recheck_position = 1 - + end function Routing:RouteUpdateRoutine() local qh = QuestHelper local map_walker = Routing.map_walker local minimap_dodad = qh.minimap_dodad - + local route = qh.route local to_add, to_remove, add_swap = qh.to_add, qh.to_remove, self.add_swap - + local routes = self.routes local pos = qh.pos - + local best_route = self.best_route - + local last_cache_clear = GetTime() - + ------ EVIL HACK OF DEBUG - + ------ EVIL HACK OF DEBUG - + while true do -- Clear caches out a bit if GetTime() + 15 >= last_cache_clear then qh:CacheCleanup() last_cache_clear = GetTime() end - + -- Update the player's position data. if qh.target then -- We know the player will be at the target location at target_time, so fudge the numbers -- to pretend we're traveling there. - + pos[1], pos[3], pos[4] = qh.target[1], qh.target[3], qh.target[4] local extra_time = math.max(0, qh.target_time-time()) for i, t in ipairs(qh.target[2]) do @@ -857,40 +857,40 @@ function Routing:RouteUpdateRoutine() if not pos[1] -- Need a valid position, in case the player was dead when they loaded the game. or not UnitIsDeadOrGhost("player") then -- Don't update the player's position if they're dead, assume they'll be returning to their corpse. - pos[3], pos[4] = qh.Astrolabe:TranslateWorldMapPosition(qh.c, qh.z, qh.x, qh.y, qh.c, 0) + pos[3], pos[4] = qh.Astrolabe:TranslateWorldMapPosition(qh.m, qh.f, qh.x, qh.y, qh.m, 0) --[[ assert(pos[3]) ]] --[[ assert(pos[4]) ]] pos[1] = qh.zone_nodes[qh.i] pos[3], pos[4] = pos[3] * qh.continent_scales_x[qh.c], pos[4] * qh.continent_scales_y[qh.c] - + for i, n in ipairs(pos[1]) do if not n.x then for i, j in pairs(n) do qh:TextOut("[%q]=%s %s", i, type(j), tostring(j) or "???") end --[[ assert(false) ]] end - + local a, b = n.x-pos[3], n.y-pos[4] pos[2][i] = math.sqrt(a*a+b*b) end end end - + local changed = false - + if #route > 0 then if self.recheck_position > #route then self.recheck_position = 1 end local o = route[self.recheck_position] - + --[[ assert(o.zones) ]] o.filter_zone = o.zones[pos[1].i] == nil o.filter_watched = not o:IsWatched() - + if not o:Known() then -- Objective was probably made to depend on an objective that we don't know about yet. -- We add it to both lists, because although we need to remove it, we need it added again when we can. -- This creates an inconsistancy, but it'll get fixed in the removal loop before anything has a chance to -- explode from it. - + to_remove[o] = true to_add[o] = true else @@ -899,28 +899,28 @@ function Routing:RouteUpdateRoutine() o.before = o.swap_before o.swap_before = nil end - + if o.swap_after then qh:ReleaseTable(o.after) o.after = o.swap_after o.swap_after = nil end - + if o.is_sharing ~= o.want_share then o.is_sharing = o.want_share - + if o.want_share then qh:DoShareObjective(o) else qh:DoUnshareObjective(o) end end - + CalcObjectivePriority(o) - + -- Make sure the objective in best_route is still in a valid position. -- Won't worry about other routes, they should forced into valid configurations by breeding. - + -- This is a temporary, horrible hack - we want to do a "best" test without actually clobbering our old route, so we're making a new temporary one to jam our route in for now. In theory, AddObjectiveBest should, I don't know, add it in the *best place*, but at the moment it does not necessarily, thus this nastiness. local aobt = {} setmetatable(aobt, getmetatable(best_route)) @@ -943,39 +943,39 @@ function Routing:RouteUpdateRoutine() end end -- Actually duplicating a route is irritatingly hard (this is another thing which will be fixed eventually dammit) - + --[[ assert(aobt:sanity()) ]] --[[ assert(best_route:sanity()) ]] - + local old_distance, old_index = best_route.distance, best_route:removeObjective(o) local old_real_distance = (best_route.distance or 0) + (best_route[1] and qh:ComputeTravelTime(pos, best_route[1].pos) or 0) -- part of hack local new_index, sanityfixed = best_route:addObjectiveBest(o, old_index, old_distance) local new_real_distance = (best_route.distance or 0) + (best_route[1] and qh:ComputeTravelTime(pos, best_route[1].pos) or 0) -- part of hack -- not sure if best_route.distance can ever be nil or not, I was just getting errors I couldn't find for a while and ended up with that test included when I fixed the real error - + if new_real_distance < old_real_distance or sanityfixed then -- More of the temporary hack -- If we're using the new path . . . - + if old_index > new_index then old_index, new_index = new_index, old_index end - + for i = math.max(1, old_index-1), new_index do local info = best_route[i] local obj = info.obj obj.pos = info.pos route[i] = obj end - - + + if old_index ~= new_index then if old_index == 1 then minimap_dodad:SetObjective(route[1]) end - + changed = true end - + -- . . . release our backup path for k, v in ipairs(aobt) do QuestHelper:ReleaseTable(v) end QuestHelper:ReleaseTable(aobt[0]) @@ -989,7 +989,7 @@ function Routing:RouteUpdateRoutine() setmetatable(aobt, Route) --[[ assert(best_route:sanity()) ]] end -- hack - + -- this chunk of code used to live up by old_index ~= new_index, but it obviously no longer does. should probably be moved back once Best works again -- Maybe the bug he's referring to is the one I'm fighting with in this chunk of code? Hey dude, if you find a bug, *fix the damn bug don't work around it* --if old_index == new_index then @@ -999,21 +999,21 @@ function Routing:RouteUpdateRoutine() -- THIS IS A GREAT IDEA --else self.recheck_position = self.recheck_position + 1 - + end end - + -- Remove any waypoints if needed. while true do local obj = next(to_remove) if not obj then break end to_remove[obj] = nil - + if obj.is_sharing then obj.is_sharing = false qh:DoUnshareObjective(obj) end - + for r in pairs(routes) do if r == best_route then local index = r:removeObjective(obj) @@ -1025,26 +1025,26 @@ function Routing:RouteUpdateRoutine() r:removeObjective(obj) end end - + obj:DoneRouting() - + changed = true end - + -- Add any waypoints if needed while true do local obj = next(to_add) if not obj then break end to_add[obj] = nil - + obj.filter_zone = obj.zones and obj.zones[pos[1].i] == nil obj.filter_watched = not obj:IsWatched() - + if obj:Known() then obj:PrepareRouting() - + obj.filter_zone = obj.zones[pos[1].i] == nil - + if obj.filter_zone and QuestHelper_Pref.filter_zone then -- Not going to add it, wrong zone. obj:DoneRouting() @@ -1054,9 +1054,9 @@ function Routing:RouteUpdateRoutine() obj.is_sharing = true qh:DoShareObjective(obj) end - + CalcObjectivePriority(obj) - + for r in pairs(routes) do if r == best_route then local index = r:addObjectiveBest(obj) @@ -1069,14 +1069,14 @@ function Routing:RouteUpdateRoutine() r:addObjectiveFast(obj) end end - + changed = true end else add_swap[obj] = true end end - + for obj in pairs(add_swap) do -- If one of the objectives we were considering adding was removed, it would be in both lists. -- That would be bad. We can't remove it because we haven't actually added it yet, so @@ -1087,21 +1087,21 @@ function Routing:RouteUpdateRoutine() add_swap[obj] = nil end end - + to_add, add_swap = add_swap, to_add qh.to_add = to_add self.add_swap = add_swap - + if #best_route > 1 then -- If there is 2 or more objectives, randomly combine routes to (hopefully) create something better than we had before. - + -- Calculate best_route first, so that if other routes are identical, we don't risk swapping with them and -- updating the map_walker. local best, max_fitness = best_route, 1/(qh:ComputeTravelTime(pos, best_route[1].pos) + best_route.distance) best_route.fitness = max_fitness - + QH_Timeslice_Yield() - + for r in pairs(routes) do if r ~= best_route then local fit = 1/(qh:ComputeTravelTime(pos, r[1].pos)+r.distance) @@ -1112,9 +1112,9 @@ function Routing:RouteUpdateRoutine() QH_Timeslice_Yield() end end - + local to_breed, score - + for r in pairs(routes) do if r ~= best then local s = math.random()*r.fitness @@ -1123,103 +1123,103 @@ function Routing:RouteUpdateRoutine() end end end - + to_breed:breed(routes) - + if 1/(qh:ComputeTravelTime(pos, to_breed[1].pos)+to_breed.distance+improve_margin) > max_fitness then best = to_breed end - + QH_Timeslice_Yield() - + if best ~= best_route then - + --[[ assert(best:sanity()) ]] --[[ assert(best_route:sanity()) ]] - + best_route = best self.best_route = best_route - + for i, info in ipairs(best) do local obj = info.obj obj.pos = info.pos route[i] = obj end - + minimap_dodad:SetObjective(route[1]) - + changed = true end end - + if qh.defered_flight_times then qh:buildFlightTimes() qh.defered_flight_times = false --[[ assert(qh.defered_graph_reset) ]] end - + if qh.defered_graph_reset then QH_Timeslice_Yield() - + for r in pairs(routes) do r:pathResetBegin() end - + qh.graph_in_limbo = true qh:ResetPathing() qh.graph_in_limbo = false qh.defered_graph_reset = false - + for r in pairs(routes) do r:pathResetEnd() end - + for i, info in ipairs(best_route) do local obj = info.obj obj.pos = info.pos route[i] = obj end best_route:recalculateDistances() - + minimap_dodad:SetObjective(route[1]) - + QuestHelper:SetTargetLocationRecalculate() - + for r in pairs(routes) do --[[ assert(r:sanity()) ]] end best_route:sanity() - + QH_Timeslice_Yield() end - + if changed then map_walker:RouteChanged() end - + --[[ assert(#route == #best_route) ]] - + -- temporary hack to cause more errors --qh.defered_graph_reset = true --qh.defered_flight_times = true - + QH_Timeslice_Yield() end end function Routing:Initialize() self:RoutingSetup() - + QH_Timeslice_Add(function() Routing:RouteUpdateRoutine() end, "routing") QH_Timeslice_Toggle("routing", false) - + --[[ if coroutine.coco then -- coco allows yielding across c boundries, which allows me to use xpcall to get -- stack traces for coroutines without calls to yield resulting in thermal nuclear meltdown. - + -- This isn't part of WoW, I was using it in my driver program: Development/routetest - + update_route = coroutine.create( function() local state, err = xpcall( @@ -1233,7 +1233,7 @@ function Routing:Initialize() return debug.traceback(tostring(err), 2) end end) - + if not state then error(err, 0) end diff --git a/QuestHelper/utility.lua b/QuestHelper/utility.lua index 843b310..3c6f2ac 100644 --- a/QuestHelper/utility.lua +++ b/QuestHelper/utility.lua @@ -30,7 +30,7 @@ local default_colour_theme = menu_text={1, 1, 1}, menu_text_highlight={0, 0, 0}, menu={0, 0, 0}, - menu_highlight={0.3, 0.5, 0.7}, + menu_highlight={0.3, 0.5, 0.7}, menu_title_text={1, 1, 1}, menu_title_text_highlight={1, 1, 1}, menu_title={0, 0.2, 0.6}, @@ -54,7 +54,7 @@ function QuestHelper:GetColourTheme() if date("%b%d") == "Dec25" then return xmas_colour_theme end - + return default_colour_theme end @@ -75,30 +75,30 @@ function QuestHelper:CreateUID(length) local characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" for k = 1, (math.floor(GetTime() % 1000) + 5) do math.random() end -- it's sort of like seeding. only worse. local base = GetUnitName("player")..":"..GetRealmName()..":"..math.random(0, 2147483647)..":"..GetTime()..":"..time() - + for c = 1,(length or 32) do local pos = 1+math.floor(self:HashString(result..base..math.random(0, 2147483647))%string.len(characters)) result = result .. string.sub(characters, pos, pos) end - + return result end function QuestHelper:ZoneSanity() local sane = true - + for c in pairs(self.Astrolabe:GetMapVirtualContinents()) do local pz = self.Astrolabe:GetMapVirtualZones(c) pz[0] = true for z in pairs(pz) do local name - + if z == 0 then name = self.Astrolabe:GetMapVirtualContinents()[c] else name = self.Astrolabe:GetMapVirtualZones(c)[z] end - + --[[ assert(name) ]] -- c,z should be equal to name, unless c = 5 and z = 0, in which case it should be equal to name .. " Continent" if QuestHelper_Zones[c][z] ~= name then @@ -106,7 +106,7 @@ function QuestHelper:ZoneSanity() QuestHelper_ErrorCatcher_ExplicitError(false, string.format("'%s' has the wrong ID (should be %d,%d).", name, c, z)) --QuestHelper:TextOut(string.format("'%s' has the wrong ID (should be %d,%d).", name, c, z)) end - + local pair = QuestHelper_ZoneLookup[name] if not pair then sane = false @@ -116,14 +116,14 @@ function QuestHelper:ZoneSanity() QuestHelper_ErrorCatcher_ExplicitError(false, string.format("ZoneLookup['%s'] maps to wrong pair. It should be (%d, %d) but is (%d, %d)", name, c, z, pair[1], pair[2])) --QuestHelper:TextOut("ZoneLookup['"..name.."'] maps to wrong pair.") end - + local index = QuestHelper_IndexLookup[name] if QuestHelper_ZoneLookup[index] ~= pair then sane = false QuestHelper_ErrorCatcher_ExplicitError(false, "ZoneLookup['"..name.."'] isn't equal to ZoneLookup["..index.."] they are "..tostring(QuestHelper_ZoneLookup[name]).." and "..tostring(QuestHelper_ZoneLookup[index])..", respectively.") --QuestHelper:TextOut("ZoneLookup['"..name.."'] isn't equal to ZoneLookup["..index.."] they are "..tostring(QuestHelper_ZoneLookup[name]).." and "..tostring(QuestHelper_ZoneLookup[index])..", respectively.") end - + if not index or QuestHelper_NameLookup[index] ~= name then sane = false QuestHelper_ErrorCatcher_ExplicitError(false, "NameLookup["..(index or "???").."] doesn't equal '"..name.."', it is "..tostring(QuestHelper_NameLookup[index])) @@ -131,7 +131,7 @@ function QuestHelper:ZoneSanity() end end end - + return sane end @@ -160,11 +160,11 @@ end function QuestHelper:GetUnitID(unit) local id = UnitGUID(unit) - + if id then return (string.sub(id, 5, 5) == "3") and tonumber(string.sub(id, 6, 12), 16) or nil end - + return nil end @@ -179,7 +179,7 @@ end function QuestHelper:CountItem(item_id) local count = 0 - + for bag = 0,NUM_BAG_SLOTS do for slot = 1,GetContainerNumSlots(bag) do local link = GetContainerItemLink(bag, slot) @@ -188,14 +188,14 @@ function QuestHelper:CountItem(item_id) end end end - + return count end function QuestHelper:ItemCooldown(item_id) local now = GetTime() local cooldown = nil - + for bag = 0,NUM_BAG_SLOTS do for slot = 1,GetContainerNumSlots(bag) do local link = GetContainerItemLink(bag, slot) @@ -213,7 +213,7 @@ function QuestHelper:ItemCooldown(item_id) end end end - + return cooldown end @@ -222,7 +222,7 @@ function QuestHelper:TimeString(seconds) --self:AppendNotificationError("2008-10-8 nil-timestring") -- we're just going to do away with this entirely, the fact is that a lot of this is going to be ripped to shreds soon anyway return "(unknown)" end - + local seconds = math.ceil(seconds) local h, m, s = math.floor(seconds/(60*60)), math.floor(seconds/60)%60, seconds%60 if h > 0 then @@ -257,20 +257,13 @@ function QuestHelper:PercentString(pct) end function QuestHelper:PlayerPosition() - return self.i, self.x, self.y + return self.m, self.f, self.x, self.y end function QuestHelper:UnitPosition(unit) - local c, z, x, y = self.Astrolabe:GetUnitPosition(unit,true) - if c then - if z == 0 then - SetMapToCurrentZone() - z = GetCurrentMapZone() - if z ~= 0 then - x, y = self.Astrolabe:TranslateWorldMapPosition(c, 0, x, y, c, z) - end - end - return QuestHelper_IndexLookup[c][z], x, y + local m, f, x, y = self.Astrolabe:GetUnitPosition(unit,true) + if m then + return m, f, x, y else return self:PlayerPosition() end @@ -290,22 +283,21 @@ function QuestHelper:Location_AbsoluteString(delayed, c, x, y) return ("[|cffffffff%s/%s,%s,%s|r]"):format(delayed and "D" or "c", c and string.format("%d", c) or tostring(c), x and string.format("%.3f", x) or tostring(x), y and string.format("%.3f", y) or tostring(y)) end -function QuestHelper:Distance(i1, x1, y1, i2, x2, y2) - local p1, p2 = QuestHelper_ZoneLookup[i1], QuestHelper_ZoneLookup[i2] - return self.Astrolabe:ComputeDistance(p1[1], p1[2], x1, y1, p2[1], p2[2], x2, y2) or 10000 +function QuestHelper:Distance(m1, x1, y1, m2, x2, y2) + return self.Astrolabe:ComputeDistance(m1, 0, x1, y1, m2, 0, x2, y2) or 10000 end function QuestHelper:AppendPosition(list, index, x, y, w, min_dist) if not x or not y or (x == 0 and y == 0) or x <= -0.1 or y <= -0.1 or x >= 1.1 or y >= 1.1 then - local nc, nz, nx, ny = self.Astrolabe:GetCurrentPlayerPosition() + local nm, nf, nx, ny = self.Astrolabe:GetCurrentPlayerPosition() --self:AppendNotificationError("2008-10-6 nil-position", string.format("nilposition, %s %s %s %s vs %s %s", tostring(nc), tostring(nz), tostring(nx), tostring(ny), tostring(x), tostring(y))) -- We're just not worrying about this too much anymore. Slash and burn. return list -- This isn't a real position. end - + local closest, distance = nil, 0 w = w or 1 min_dist = min_dist or 200 - + for i, p in ipairs(list) do if index == p[1] then local d = self:Distance(index, x, y, p[1], p[2], p[3]) @@ -314,7 +306,7 @@ function QuestHelper:AppendPosition(list, index, x, y, w, min_dist) end end end - + if closest and distance < min_dist then local p = list[closest] p[2] = (p[2]*p[4]+x*w)/(p[4]+w) @@ -323,7 +315,7 @@ function QuestHelper:AppendPosition(list, index, x, y, w, min_dist) else table.insert(list, {index, x, y, w}) end - + return list end @@ -459,6 +451,6 @@ function QH_fixedmessage(text) whileDead = 1, hideOnEscape = 1 } - + StaticPopup_Show(msgtext) end