local GetTime = QuestHelper_GetTime QuestHelper_File["graph_flightpath.lua"] = "4.0.1.$svnversion$" QuestHelper_Loadtime["graph_flightpath.lua"] = GetTime() -- Name to Name, gives {time, accurate} QH_Flight_Distances = {} QH_Flight_Destinations = {} local rlevel = nil local cwf = nil function QH_debug_flightpath() print(rlevel, cwf) end function QH_redo_flightpath() QuestHelper: Assert(DB_Ready()) local globby if QuestHelper.loading_flightpath then globby = QuestHelper.loading_flightpath else QuestHelper.flightpathing = QuestHelper.CreateLoadingCounter() globby = QuestHelper.flightpathing end local load_earlyload = globby:MakeSubcategory(1) local load_preroll = globby:MakeSubcategory(1) local load_floyd = globby:MakeSubcategory(1) local load_postroll = globby:MakeSubcategory(0.1) load_preroll:SetPercentage(0) -- First, let's figure out if the player can fly. -- The logic we're using: if he has 225 or 300, then he can fly in Outland. If he's got Cold Weather Flying and those levels, he can fly in Northrend. if true then 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_cwf = not not GetSpellInfo(GetSpellInfo(54197)) local speed local cull if ridingLevel == 225 then speed = 17.5 cull = false elseif ridingLevel == 300 then speed = 27 cull = true end if ridingLevel >= 225 then QH_Graph_Flyplaneset(3, speed, cull) -- Outland end if ridingLevel >= 225 and has_cwf then QH_Graph_Flyplaneset(4, speed, cull) -- Northrend end local has_fmsl = not not GetSpellInfo(GetSpellInfo(90267)) if ridingLevel >= 225 and has_fmsl then QH_Graph_Flyplaneset(5, speed, cull) QH_Graph_Flyplaneset(2, speed, cull) QH_Graph_Flyplaneset(1, speed, cull) end rlevel = ridingLevel cwf = has_cwf else QuestHelper:TextOut("Horrible QH hack, mount flight disabled, please inform Zorba if this is in a release version") end local flightids = DB_ListItems("flightmasters") local flightdb = {} local has = {} local has_count = 0 local fidcount = 0 for k, v in pairs(flightids) do flightdb[v] = DB_GetItem("flightmasters", v, true, true) if QuestHelper_KnownFlightRoutes[flightdb[v].name] then has[k] = true has_count = has_count + 1 end fidcount = fidcount + 1 load_earlyload:SetPercentage(fidcount / QuestHelper:TableSize(flightids)) end local adjacency = {} local important = {} QH_Timeslice_Yield() local has_seen = 0 for k, v in pairs(has) do local tdb = DB_GetItem("flightpaths", k, true, true) if tdb then for dest, dat in pairs(tdb) do if has[dest] then for _, route in ipairs(dat) do local passes = true if route.path then for _, intermed in ipairs(route.path) do if not has[intermed] then passes = false break end end end if passes then --QuestHelper:TextOut(string.format("Found link between %s and %s, cost %f", flightdb[k].name, flightdb[dest].name, route.distance)) if not adjacency[k] then adjacency[k] = {} end if not adjacency[dest] then adjacency[dest] = {} end QuestHelper: Assert(not (adjacency[k][dest] and adjacency[k][dest].time)) adjacency[k][dest] = {time = route.distance, dist = route.distance, original = true} -- no such thing as strongly asymmetric routes -- note that we're only hitting up adjacency here, because we don't have "time info" if not adjacency[dest][k] then adjacency[dest][k] = {dist = route.distance * 1.1, original = true} -- It's original because, in theory, we may end up basing other links on this one. It's still not time-authoritative, though. end important[k] = true important[dest] = true break end end end end DB_ReleaseItem(tdb) end has_seen = has_seen + 1 load_preroll:SetPercentage(has_seen / has_count) end QH_Timeslice_Yield() local imp_flat = {} local flightmasters = {} for k, v in pairs(important) do table.insert(imp_flat, k) if flightdb[k].mid then local fmx = DB_GetItem("monster", flightdb[k].mid, true, true) if fmx and fmx.loc then flightmasters[k] = QuestHelper:CreateTable("flightmaster cachey") for tk, v in pairs(fmx.loc[1]) do if not tk:match("__.*") then flightmasters[k][tk] = v --[[ QuestHelper:Assert(type(tk) ~= "table") ]] --[[ QuestHelper:Assert(type(v) ~= "table") ]] end end else --QuestHelper:TextOut(string.format("Missing flightmaster location for node %d/%s", k, tostring(flightdb[k].name))) end if fmx then DB_ReleaseItem(fmx) end else --QuestHelper:TextOut(string.format("Missing flightmaster for node %d/%s", k, tostring(flightdb[k].name))) end end table.sort(imp_flat) for _, v in ipairs(imp_flat) do adjacency[v] = adjacency[v] or {} end for idx, pivot in ipairs(imp_flat) do QH_Timeslice_Yield() for _, i in ipairs(imp_flat) do for _, j in ipairs(imp_flat) do if adjacency[i][pivot] and adjacency[pivot][j] then local cst = adjacency[i][pivot].dist + adjacency[pivot][j].dist if not adjacency[i][j] or adjacency[i][j].dist > cst then if not adjacency[i][j] then adjacency[i][j] = {} end adjacency[i][j].dist = cst adjacency[i][j].original = nil end end end end load_floyd:SetPercentage(idx / #imp_flat) end QH_Timeslice_Yield() do local clustaken = {} for src, t in pairs(adjacency) do if not clustaken[src] then local tcst = {} local tcct = 0 local ctd = {} table.insert(ctd, src) while #ctd > 0 do local ite = table.remove(ctd) QuestHelper: Assert(not clustaken[ite] or tcst[ite]) if not tcst[ite] then clustaken[ite] = true tcst[ite] = true for _, dst in pairs(imp_flat) do if adjacency[ite][dst] and not tcst[dst] then table.insert(ctd, dst) end end tcct = tcct + 1 end end --QuestHelper: TextOut(string.format("Starting with %d, cluster of %d", src, tcct)) end end end QH_Graph_Plane_Destroylinks("flightpath") -- reset! QH_Flight_Distances = {} QH_Flight_Destinations = {} for src, t in pairs(adjacency) do QH_Timeslice_Yield() for dest, dat in pairs(t) do do local fms = flightmasters[src] local fmd = flightmasters[dest] if fms and fmd then local fmsc = QuestHelper_ParentLookup[fms.p] local fmdc = QuestHelper_ParentLookup[fmd.p] QuestHelper: Assert(fmsc == fmdc) end end if not QH_Flight_Destinations[dest] and flightmasters[dest] then local fmd = flightmasters[dest] QH_Flight_Destinations[flightdb[dest].name] = {x = fmd.x, y = fmd.y, c = QuestHelper_ParentLookup[fmd.p], p = fmd.p} end do local sname = flightdb[src].name local dname = flightdb[dest].name if not QH_Flight_Distances[sname] then QH_Flight_Distances[sname] = {} end QuestHelper: Assert(not QH_Flight_Distances[sname][dname]) QH_Flight_Distances[sname][dname] = {adjacency[src][dest].dist, not adjacency[src][dest].original} end if dat.original and not (src > dest and adjacency[dest][src] and adjacency[dest][src].original) then local fms = flightmasters[src] local fmd = flightmasters[dest] if fms and fmd then local snode = {x = fms.x, y = fms.y, c = QuestHelper_ParentLookup[fms.p], p = fms.p, map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("FLIGHT_POINT", flightdb[src].name))}, condense_class = "flightpath"} local dnode = {x = fmd.x, y = fmd.y, c = QuestHelper_ParentLookup[fmd.p], p = fmd.p, map_desc = {QHFormat("WAYPOINT_REASON", QHFormat("FLIGHT_POINT", flightdb[dest].name))}, condense_class = "flightpath"} local ret = adjacency[dest][src] and adjacency[dest][src].original and adjacency[dest][src].dist QH_Graph_Plane_Makelink("flightpath", snode, dnode, dat.dist, ret) end end end end for _, v in pairs(flightdb) do DB_ReleaseItem(v) end for _, v in pairs(flightmasters) do QuestHelper:ReleaseTable(v) end load_postroll:SetPercentage(1) if not QuestHelper.loading_flightpath then QuestHelper.flightpathing = nil end QH_Graph_Plane_Refresh() end