take two
[QuestHelper.git] / graph_flightpath.lua
blob62277fecaac39aacd5eee7c627cce1a441d6bfb5
1 QuestHelper_File["graph_flightpath.lua"] = "Development Version"
2 QuestHelper_Loadtime["graph_flightpath.lua"] = GetTime()
4 -- Name to Name, gives {time, accurate}
5 QH_Flight_Distances = {}
6 QH_Flight_Destinations = {}
8 local rlevel = nil
9 local cwf = nil
11 function QH_debug_flightpath()
12 print(rlevel, cwf)
13 end
15 function QH_redo_flightpath()
16 QuestHelper: Assert(DB_Ready())
18 local globby
19 if QuestHelper.loading_flightpath then
20 globby = QuestHelper.loading_flightpath
21 else
22 QuestHelper.flightpathing = QuestHelper.CreateLoadingCounter()
23 globby = QuestHelper.flightpathing
24 end
26 local load_earlyload = globby:MakeSubcategory(1)
27 local load_preroll = globby:MakeSubcategory(1)
28 local load_floyd = globby:MakeSubcategory(1)
29 local load_postroll = globby:MakeSubcategory(0.1)
31 load_preroll:SetPercentage(0)
33 -- First, let's figure out if the player can fly.
34 -- 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.
36 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
37 local has_cwf = not not GetSpellInfo(GetSpellInfo(54197))
39 local speed
40 if ridingLevel == 225 then
41 speed = 11
42 elseif ridingLevel == 300 then
43 speed = 27
44 end
46 if ridingLevel >= 225 then
47 QH_Graph_Flyplaneset(3, speed) -- Outland
48 end
50 if ridingLevel >= 225 and has_cwf then
51 QH_Graph_Flyplaneset(4, speed) -- Northrend
52 end
54 rlevel = ridingLevel
55 cwf = has_cwf
56 end
58 local flightids = DB_ListItems("flightmasters")
59 local flightdb = {}
61 local has = {}
62 local has_count = 0
64 local fidcount = 0
65 for k, v in pairs(flightids) do
66 flightdb[v] = DB_GetItem("flightmasters", v, true, true)
67 if QuestHelper_KnownFlightRoutes[flightdb[v].name] then
68 has[k] = true
69 has_count = has_count + 1
70 end
72 fidcount = fidcount + 1
73 load_earlyload:SetPercentage(fidcount / QuestHelper:TableSize(flightids))
74 end
76 local adjacency = {}
78 local important = {}
80 QH_Timeslice_Yield()
82 local has_seen = 0
83 for k, v in pairs(has) do
84 local tdb = DB_GetItem("flightpaths", k, true, true)
85 if tdb then
86 for dest, dat in pairs(tdb) do
87 if has[dest] then
88 for _, route in ipairs(dat) do
89 local passes = true
90 if route.path then for _, intermed in ipairs(route.path) do
91 if not has[intermed] then passes = false break end
92 end end
94 if passes then
95 --QuestHelper:TextOut(string.format("Found link between %s and %s, cost %f", flightdb[k].name, flightdb[dest].name, route.distance))
96 if not adjacency[k] then adjacency[k] = {} end
97 if not adjacency[dest] then adjacency[dest] = {} end
98 QuestHelper: Assert(not (adjacency[k][dest] and adjacency[k][dest].time))
99 adjacency[k][dest] = {time = route.distance, dist = route.distance, original = true}
101 -- no such thing as strongly asymmetric routes
102 -- note that we're only hitting up adjacency here, because we don't have "time info"
103 if not adjacency[dest][k] then
104 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.
107 important[k] = true
108 important[dest] = true
109 break
114 DB_ReleaseItem(tdb)
117 has_seen = has_seen + 1
118 load_preroll:SetPercentage(has_seen / has_count)
121 QH_Timeslice_Yield()
123 local imp_flat = {}
124 local flightmasters = {}
125 for k, v in pairs(important) do
126 table.insert(imp_flat, k)
127 if flightdb[k].mid then
128 local fmx = DB_GetItem("monster", flightdb[k].mid, true, true)
129 if fmx.loc then
130 flightmasters[k] = QuestHelper:CreateTable("flightmaster cachey")
131 for tk, v in pairs(fmx.loc[1]) do
132 if not tk:match("__.*") then
133 flightmasters[k][tk] = v
134 QuestHelper:Assert(type(tk) ~= "table")
135 QuestHelper:Assert(type(v) ~= "table")
138 else
139 --QuestHelper:TextOut(string.format("Missing flightmaster location for node %d/%s", k, tostring(flightdb[k].name)))
141 DB_ReleaseItem(fmx)
142 else
143 --QuestHelper:TextOut(string.format("Missing flightmaster for node %d/%s", k, tostring(flightdb[k].name)))
146 table.sort(imp_flat)
148 for _, v in ipairs(imp_flat) do
149 adjacency[v] = adjacency[v] or {}
152 for idx, pivot in ipairs(imp_flat) do
153 QH_Timeslice_Yield()
154 for _, i in ipairs(imp_flat) do
155 for _, j in ipairs(imp_flat) do
156 if adjacency[i][pivot] and adjacency[pivot][j] then
157 local cst = adjacency[i][pivot].dist + adjacency[pivot][j].dist
158 if not adjacency[i][j] or adjacency[i][j].dist > cst then
159 if not adjacency[i][j] then adjacency[i][j] = {} end
160 adjacency[i][j].dist = cst
161 adjacency[i][j].original = nil
167 load_floyd:SetPercentage(idx / #imp_flat)
170 QH_Timeslice_Yield()
173 local clustaken = {}
175 for src, t in pairs(adjacency) do
176 if not clustaken[src] then
177 local tcst = {}
178 local tcct = 0
179 local ctd = {}
180 table.insert(ctd, src)
182 while #ctd > 0 do
183 local ite = table.remove(ctd)
184 QuestHelper: Assert(not clustaken[ite] or tcst[ite])
186 if not tcst[ite] then
187 clustaken[ite] = true
188 tcst[ite] = true
189 for _, dst in pairs(imp_flat) do
190 if adjacency[ite][dst] and not tcst[dst] then
191 table.insert(ctd, dst)
195 tcct = tcct + 1
199 --QuestHelper: TextOut(string.format("Starting with %d, cluster of %d", src, tcct))
204 QH_Graph_Plane_Destroylinks("flightpath")
206 -- reset!
207 QH_Flight_Distances = {}
208 QH_Flight_Destinations = {}
210 for src, t in pairs(adjacency) do
211 QH_Timeslice_Yield()
213 for dest, dat in pairs(t) do
215 local fms = flightmasters[src]
216 local fmd = flightmasters[dest]
217 if fms and fmd then
218 local fmsc = QuestHelper_ParentLookup[fms.p]
219 local fmdc = QuestHelper_ParentLookup[fmd.p]
220 QuestHelper: Assert(fmsc == fmdc)
224 if not QH_Flight_Destinations[dest] and flightmasters[dest] then
225 local fmd = flightmasters[dest]
226 QH_Flight_Destinations[flightdb[dest].name] = {x = fmd.x, y = fmd.y, c = QuestHelper_ParentLookup[fmd.p], p = fmd.p}
230 local sname = flightdb[src].name
231 local dname = flightdb[dest].name
233 if not QH_Flight_Distances[sname] then QH_Flight_Distances[sname] = {} end
234 QuestHelper: Assert(not QH_Flight_Distances[sname][dname])
235 QH_Flight_Distances[sname][dname] = {adjacency[src][dest].dist, not adjacency[src][dest].original}
238 if dat.original and not (src > dest and adjacency[dest][src] and adjacency[dest][src].original) then
239 local fms = flightmasters[src]
240 local fmd = flightmasters[dest]
241 if fms and fmd then
242 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[dest].name))}, condense_class = "flightpath"}
243 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[src].name))}, condense_class = "flightpath"}
245 local ret = adjacency[dest][src] and adjacency[dest][src].original and adjacency[dest][src].dist
246 QH_Graph_Plane_Makelink("flightpath", snode, dnode, dat.dist, ret)
252 for _, v in pairs(flightdb) do
253 DB_ReleaseItem(v)
255 for _, v in pairs(flightmasters) do
256 QuestHelper:ReleaseTable(v)
259 load_postroll:SetPercentage(1)
261 if not QuestHelper.loading_flightpath then
262 QuestHelper.flightpathing = nil