remove debug, add some optimization?
[QuestHelper.git] / graph_flightpath.lua
blob603108904f167e533f485db8adac561b883a37af
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 local cull
41 if ridingLevel == 225 then
42 speed = 17.5
43 cull = false
44 elseif ridingLevel == 300 then
45 speed = 27
46 cull = false
47 end
49 if ridingLevel >= 225 then
50 QH_Graph_Flyplaneset(3, speed, cull) -- Outland
51 end
53 if ridingLevel >= 225 and has_cwf then
54 QH_Graph_Flyplaneset(4, speed, cull) -- Northrend
55 end
57 rlevel = ridingLevel
58 cwf = has_cwf
59 end
61 local flightids = DB_ListItems("flightmasters")
62 local flightdb = {}
64 local has = {}
65 local has_count = 0
67 local fidcount = 0
68 for k, v in pairs(flightids) do
69 flightdb[v] = DB_GetItem("flightmasters", v, true, true)
70 if QuestHelper_KnownFlightRoutes[flightdb[v].name] then
71 has[k] = true
72 has_count = has_count + 1
73 end
75 fidcount = fidcount + 1
76 load_earlyload:SetPercentage(fidcount / QuestHelper:TableSize(flightids))
77 end
79 local adjacency = {}
81 local important = {}
83 QH_Timeslice_Yield()
85 local has_seen = 0
86 for k, v in pairs(has) do
87 local tdb = DB_GetItem("flightpaths", k, true, true)
88 if tdb then
89 for dest, dat in pairs(tdb) do
90 if has[dest] then
91 for _, route in ipairs(dat) do
92 local passes = true
93 if route.path then for _, intermed in ipairs(route.path) do
94 if not has[intermed] then passes = false break end
95 end end
97 if passes then
98 --QuestHelper:TextOut(string.format("Found link between %s and %s, cost %f", flightdb[k].name, flightdb[dest].name, route.distance))
99 if not adjacency[k] then adjacency[k] = {} end
100 if not adjacency[dest] then adjacency[dest] = {} end
101 QuestHelper: Assert(not (adjacency[k][dest] and adjacency[k][dest].time))
102 adjacency[k][dest] = {time = route.distance, dist = route.distance, original = true}
104 -- no such thing as strongly asymmetric routes
105 -- note that we're only hitting up adjacency here, because we don't have "time info"
106 if not adjacency[dest][k] then
107 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.
110 important[k] = true
111 important[dest] = true
112 break
117 DB_ReleaseItem(tdb)
120 has_seen = has_seen + 1
121 load_preroll:SetPercentage(has_seen / has_count)
124 QH_Timeslice_Yield()
126 local imp_flat = {}
127 local flightmasters = {}
128 for k, v in pairs(important) do
129 table.insert(imp_flat, k)
130 if flightdb[k].mid then
131 local fmx = DB_GetItem("monster", flightdb[k].mid, true, true)
132 if fmx.loc then
133 flightmasters[k] = QuestHelper:CreateTable("flightmaster cachey")
134 for tk, v in pairs(fmx.loc[1]) do
135 if not tk:match("__.*") then
136 flightmasters[k][tk] = v
137 QuestHelper:Assert(type(tk) ~= "table")
138 QuestHelper:Assert(type(v) ~= "table")
141 else
142 --QuestHelper:TextOut(string.format("Missing flightmaster location for node %d/%s", k, tostring(flightdb[k].name)))
144 DB_ReleaseItem(fmx)
145 else
146 --QuestHelper:TextOut(string.format("Missing flightmaster for node %d/%s", k, tostring(flightdb[k].name)))
149 table.sort(imp_flat)
151 for _, v in ipairs(imp_flat) do
152 adjacency[v] = adjacency[v] or {}
155 for idx, pivot in ipairs(imp_flat) do
156 QH_Timeslice_Yield()
157 for _, i in ipairs(imp_flat) do
158 for _, j in ipairs(imp_flat) do
159 if adjacency[i][pivot] and adjacency[pivot][j] then
160 local cst = adjacency[i][pivot].dist + adjacency[pivot][j].dist
161 if not adjacency[i][j] or adjacency[i][j].dist > cst then
162 if not adjacency[i][j] then adjacency[i][j] = {} end
163 adjacency[i][j].dist = cst
164 adjacency[i][j].original = nil
170 load_floyd:SetPercentage(idx / #imp_flat)
173 QH_Timeslice_Yield()
176 local clustaken = {}
178 for src, t in pairs(adjacency) do
179 if not clustaken[src] then
180 local tcst = {}
181 local tcct = 0
182 local ctd = {}
183 table.insert(ctd, src)
185 while #ctd > 0 do
186 local ite = table.remove(ctd)
187 QuestHelper: Assert(not clustaken[ite] or tcst[ite])
189 if not tcst[ite] then
190 clustaken[ite] = true
191 tcst[ite] = true
192 for _, dst in pairs(imp_flat) do
193 if adjacency[ite][dst] and not tcst[dst] then
194 table.insert(ctd, dst)
198 tcct = tcct + 1
202 --QuestHelper: TextOut(string.format("Starting with %d, cluster of %d", src, tcct))
207 QH_Graph_Plane_Destroylinks("flightpath")
209 -- reset!
210 QH_Flight_Distances = {}
211 QH_Flight_Destinations = {}
213 for src, t in pairs(adjacency) do
214 QH_Timeslice_Yield()
216 for dest, dat in pairs(t) do
218 local fms = flightmasters[src]
219 local fmd = flightmasters[dest]
220 if fms and fmd then
221 local fmsc = QuestHelper_ParentLookup[fms.p]
222 local fmdc = QuestHelper_ParentLookup[fmd.p]
223 QuestHelper: Assert(fmsc == fmdc)
227 if not QH_Flight_Destinations[dest] and flightmasters[dest] then
228 local fmd = flightmasters[dest]
229 QH_Flight_Destinations[flightdb[dest].name] = {x = fmd.x, y = fmd.y, c = QuestHelper_ParentLookup[fmd.p], p = fmd.p}
233 local sname = flightdb[src].name
234 local dname = flightdb[dest].name
236 if not QH_Flight_Distances[sname] then QH_Flight_Distances[sname] = {} end
237 QuestHelper: Assert(not QH_Flight_Distances[sname][dname])
238 QH_Flight_Distances[sname][dname] = {adjacency[src][dest].dist, not adjacency[src][dest].original}
241 if dat.original and not (src > dest and adjacency[dest][src] and adjacency[dest][src].original) then
242 local fms = flightmasters[src]
243 local fmd = flightmasters[dest]
244 if fms and fmd then
245 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"}
246 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"}
248 local ret = adjacency[dest][src] and adjacency[dest][src].original and adjacency[dest][src].dist
249 QH_Graph_Plane_Makelink("flightpath", snode, dnode, dat.dist, ret)
255 for _, v in pairs(flightdb) do
256 DB_ReleaseItem(v)
258 for _, v in pairs(flightmasters) do
259 QuestHelper:ReleaseTable(v)
262 load_postroll:SetPercentage(1)
264 if not QuestHelper.loading_flightpath then
265 QuestHelper.flightpathing = nil
268 QH_Graph_Plane_Refresh()