split some files
[QuestHelper.git] / compile_lib.lua
blob36df0c4b441d64f570e4597c6c25c2033925fce4
2 -- I don't know why print is giving me so much trouble, but it is, sooooo
3 print = function (...)
4 local pad = ""
5 for i = 1, select("#", ...) do
6 io.stdout:write(pad)
7 local tst = tostring(select(i, ...))
8 pad = (" "):rep(#tst - math.floor(#tst / 6) * 6 + 4)
9 io.stdout:write(tst)
10 end
11 io.stdout:write("\n")
12 end
15 require("luarocks.require")
16 require("persistence")
17 require("compile_chain")
18 require("compile_debug")
19 require("bit")
20 require("pluto")
21 require("gzio")
24 ll, err = package.loadlib("/nfs/build/libcompile_core.so", "init")
25 if not ll then print(err) return end
26 ll()
29 -- we pretend to be WoW
32 local world = {}
33 world.QuestHelper_File = {}
34 world.QuestHelper_Loadtime = {}
35 world.GetTime = function() return 0 end
36 world.QuestHelper = { Assert = function (self, ...) assert(...) end, CreateTable = function() return {} end, ReleaseTable = function() end, IsWrath32 = function () return false end }
37 world.string = string
38 world.table = table
39 world.assert = assert
40 world.bit = {mod = function(a, b) return a - math.floor(a / b) * b end, lshift = bit.lshift, rshift = bit.rshift, band = bit.band}
41 world.math = math
42 world.strbyte = string.byte
43 world.strchar = string.char
44 world.pairs = pairs
45 world.ipairs = ipairs
46 world.print = function(...) print(...) end
47 world.QH_Timeslice_Yield = function() end
48 setfenv(loadfile("../questhelper/collect_merger.lua"), world)()
49 setfenv(loadfile("../questhelper/collect_bitstream.lua"), world)()
50 setfenv(loadfile("../questhelper/collect_lzw.lua"), world)()
51 local api = {}
52 world.QH_Collect_Merger_Init(nil, api)
53 world.QH_Collect_Bitstream_Init(nil, api)
54 world.QH_Collect_LZW_Init(nil, api)
55 LZW = api.Utility_LZW
56 Merger = api.Utility_Merger
57 Bitstream = api.Utility_Bitstream
58 assert(Merger.Add)
59 end
64 local world = {}
65 local cropy = {
66 "string",
67 "tonumber",
68 "print",
69 "setmetatable",
70 "type",
71 "table",
72 "tostring",
73 "error",
74 "math",
75 "coroutine",
76 "pairs",
77 "ipairs",
78 "select",
80 for _, v in ipairs(cropy) do
81 world[v] = _G[v]
82 end
83 world.getfenv = function (x) assert(x == 0 or not x) return world end
86 world._G = world
87 world.GetPlayerFacing = function () return 0 end
88 world.MinimapCompassTexture = {GetTexCoord = function() return 0, 1 end}
89 world.CreateFrame = function () return {Hide = function () end, SetParent = function () end, UnregisterAllEvents = function () end, RegisterEvent = function () end, SetScript = function () end} end
90 world.GetMapContinents = function () return "Kalimdor", "Eastern Kingdoms", "Outland", "Northrend" end
91 world.GetMapZones = function (z)
92 local db = {
93 {"Ashenvale", "Azshara", "Azuremyst Isle", "Bloodmyst Isle", "Darkshore", "Darnassus", "Desolace", "Durotar", "Dustwallow Marsh", "Felwood", "Feralas", "Moonglade", "Mulgore", "Orgrimmar", "Silithus", "Stonetalon Mountains", "Tanaris", "Teldrassil", "The Barrens", "The Exodar", "Thousand Needles", "Thunder Bluff", "Un'Goro Crater", "Winterspring"},
94 {"Alterac Mountains", "Arathi Highlands", "Badlands", "Blasted Lands", "Burning Steppes", "Deadwind Pass", "Dun Morogh", "Duskwood", "Eastern Plaguelands", "Elwynn Forest", "Eversong Woods", "Ghostlands", "Hillsbrad Foothills", "Ironforge", "Isle of Quel'Danas", "Loch Modan", "Redridge Mountains", "Searing Gorge", "Silvermoon City", "Silverpine Forest", "Stormwind City", "Stranglethorn Vale", "Swamp of Sorrows", "The Hinterlands", "Tirisfal Glades", "Undercity", "Western Plaguelands", "Westfall", "Wetlands"},
95 {"Blade's Edge Mountains", "Hellfire Peninsula", "Nagrand", "Netherstorm", "Shadowmoon Valley", "Shattrath City", "Terokkar Forest", "Zangarmarsh"},
96 {"Borean Tundra", "Crystalsong Forest", "Dalaran", "Dragonblight", "Grizzly Hills", "Howling Fjord", "Icecrown", "Sholazar Basin", "The Storm Peaks", "Wintergrasp", "Zul'Drak"},
98 return unpack(db[z])
99 end
101 local tc, tz
102 world.SetMapZoom = function (c, z) tc, tz = c, z end
103 world.GetMapInfo = function ()
104 local db = {
105 {"Ashenvale", "Aszhara", "AzuremystIsle", "BloodmystIsle", "Darkshore", "Darnassis", "Desolace", "Durotar", "Dustwallow", "Felwood", "Feralas", "Moonglade", "Mulgore", "Ogrimmar", "Silithus", "StonetalonMountains", "Tanaris", "Teldrassil", "Barrens", "TheExodar", "ThousandNeedles", "ThunderBluff", "UngoroCrater", "Winterspring", [0] = "Kalimdor"},
106 {"Alterac", "Arathi", "Badlands", "BlastedLands", "BurningSteppes", "DeadwindPass", "DunMorogh", "Duskwood", "EasternPlaguelands", "Elwynn", "EversongWoods", "Ghostlands", "Hilsbrad", "Ironforge", "Sunwell", "LochModan", "Redridge", "SearingGorge", "SilvermoonCity", "Silverpine", "Stormwind", "Stranglethorn", "SwampOfSorrows", "Hinterlands", "Tirisfal", "Undercity", "WesternPlaguelands", "Westfall", "Wetlands", [0] = "Azeroth"},
107 {"BladesEdgeMountains", "Hellfire", "Nagrand", "Netherstorm", "ShadowmoonValley", "ShattrathCity", "TerokkarForest", "Zangarmarsh", [0] = "Expansion01"},
108 {"BoreanTundra", "CrystalsongForest", "Dalaran", "Dragonblight", "GrizzlyHills", "HowlingFjord", "IcecrownGlacier", "SholazarBasin", "TheStormPeaks", "LakeWintergrasp", "ZulDrak", [0] = "Northrend"},
111 return db[tc][tz]
113 world.IsLoggedIn = function () end
115 world.QuestHelper_File = {}
116 world.QuestHelper_Loadtime = {}
117 world.GetTime = function() return 0 end
118 world.QuestHelper = { Assert = function (self, ...) assert(...) end, CreateTable = function() return {} end, ReleaseTable = function() end, TextOut = function(qh, ...) print(...) end, IsWrath32 = function () return false end }
120 setfenv(loadfile("../questhelper/AstrolabeQH/DongleStub.lua"), world)()
121 setfenv(loadfile("../questhelper/AstrolabeQH/AstrolabeMapMonitor.lua"), world)()
122 setfenv(loadfile("../questhelper/AstrolabeQH/Astrolabe.lua"), world)()
123 setfenv(loadfile("../questhelper/upgrade.lua"), world)()
125 world.QuestHelper.Astrolabe = world.DongleStub("Astrolabe-0.4-QuestHelper")
126 Astrolabe = world.QuestHelper.Astrolabe
127 assert(Astrolabe)
129 world.QuestHelper_BuildZoneLookup()
131 QuestHelper_IndexLookup = world.QuestHelper_IndexLookup
132 QuestHelper_ZoneLookup = world.QuestHelper_ZoneLookup
135 -- LuaSrcDiet embedding
137 local world = {arg = {}}
138 world.string = string
139 world.table = table
140 world.pcall = pcall
141 world.print = print
142 world.ipairs = ipairs
143 world.TEST = true
144 setfenv(loadfile("LuaSrcDiet.lua"), world)()
145 world.TEST = false
146 world.error = error
147 world.tonumber = tonumber
149 local files = {input = {}, output = {}}
151 local function readgeneral(target)
152 local rv = target[target.cline]
153 target.cline = target.cline + 1
154 return rv
157 world.io = {
158 open = function(fname, typ)
159 if fname == "input" then
160 assert(typ == "rb")
161 return {
162 read = function(_, wut)
163 assert(wut == "*l")
164 return readgeneral(files.input)
165 end,
166 close = function() end
168 elseif fname == "output" then
170 if typ == "wb" then
171 return {
172 write = function(_, wut, nilo)
173 assert(not nilo)
174 assert(not files.output_beta)
175 Merger.Add(files.output, wut)
176 end,
177 close = function() end
179 elseif typ == "rb" then
180 files.output_beta = {}
181 for k in Merger.Finish(files.output):gmatch("[^\n]*") do
182 table.insert(files.output_beta, k)
184 files.output_beta.cline = 1
186 return {
187 read = function(_, wut)
188 assert(wut == "*l")
189 return readgeneral(files.output_beta)
190 end,
191 close = function() end
193 else
194 assert()
198 end,
199 close = function() end,
200 stdout = io.stdout,
203 Diet = function(inp)
204 world.arg = {"input", "-o", "output", "--quiet", "--maximum"}
205 files.input = {}
206 for k in inp:gmatch("[^\n]*") do
207 table.insert(files.input, k)
209 files.input.cline = 1
210 files.output = {}
211 files.output_beta = nil
213 local ok = pcall(world.main)
214 if not ok then return end
216 return Merger.Finish(files.output)
219 --assert(Diet(" q = 15 ") == "q=15")
220 --assert(Diet(" jbx = 15 ") == "jbx=15")
221 --return
225 ChainBlock_Init("/nfs/build", "compile.lua", function ()
226 os.execute("rm -rf intermed")
227 os.execute("mkdir intermed")
229 os.execute("rm -rf final")
230 os.execute("mkdir final") end, ...)
232 math.umod = function (val, med)
233 if val < 0 then
234 return math.mod(val + math.ceil(-val / med + 10) * med, med)
235 else
236 return math.mod(val, med)
240 zone_image_chunksize = 1024
241 zone_image_descale = 4
242 zone_image_outchunk = zone_image_chunksize / zone_image_descale
244 zonecolors = {}
246 --[[
247 *****************************************************************
248 Utility functions
251 function version_parse(x)
252 if not x then return end
254 local rv = {}
255 for t in x:gmatch("[%d]+") do
256 table.insert(rv, tonumber(t))
258 return rv
261 function sortversion(a, b)
262 local ap, bp = version_parse(a), version_parse(b)
263 if not ap and not bp then return false end
264 if not ap then return false end
265 if not bp then return true end
266 for x = 1, #ap do
267 if ap[x] ~= bp[x] then
268 return ap[x] > bp[x]
271 return false
274 function tablesize(tab)
275 local ct = 0
276 for _, _ in pairs(tab) do
277 ct = ct + 1
279 return ct
282 function loc_version(ver)
283 local major = ver:match("([0-9])%..*")
284 if major == "0" then
285 return sortversion("0.96", ver) and 0 or 1
286 elseif major == "1" then
287 return sortversion("1.0.2", ver) and 0 or 1
288 else
289 assert()
293 function convert_loc(loc, locale)
294 if not loc then return end
295 assert(locale)
296 if locale ~= "enUS" then return end -- arrrgh, to be fixed eventually
298 local lr = loc.relative
299 if loc.relative then
300 loc.c, loc.x, loc.y = Astrolabe:GetAbsoluteContinentPosition(loc.rc, loc.rz, loc.x, loc.y)
301 loc.relative = false
304 if not loc.c or not QuestHelper_IndexLookup[loc.rc] then return end
306 if not QuestHelper_IndexLookup[loc.rc] or not QuestHelper_IndexLookup[loc.rc][loc.rz] then
307 print(loc.c, loc.rc, loc.rz, QuestHelper_IndexLookup, QuestHelper_IndexLookup[loc.rc])
308 print(loc.c, loc.rc, loc.rz, QuestHelper_IndexLookup, QuestHelper_IndexLookup[loc.rc], QuestHelper_IndexLookup[loc.rc][loc.rz])
310 loc.p = QuestHelper_IndexLookup[loc.rc][loc.rz]
311 loc.rc, loc.rz = nil, nil
313 return loc
316 function convert_multiple_loc(locs, locale)
317 if not locs then return end
319 for _, v in ipairs(locs) do
320 if v.loc then
321 convert_loc(v.loc, locale)
326 --[[
327 *****************************************************************
328 Weighted multi-concept accumulation
331 function weighted_concept_finalize(data, fraction, minimum, total_needed)
332 if #data == 0 then return end
334 fraction = fraction or 0.9
335 minimum = minimum or 1
337 table.sort(data, function (a, b) return a.w > b.w end)
339 local tw = total_needed
340 if not tw then
341 tw = 0
342 for _, v in ipairs(data) do
343 tw = tw + v.w
347 local ept
348 local wacu = 0
349 for k, v in ipairs(data) do
350 wacu = wacu + v.w
351 v.w = nil
352 if wacu >= tw * fraction or (data[k + 1] and data[k + 1].w < minimum) or not data[k + 1] then
353 ept = k
354 break
358 if not ept then
359 print(total_needed)
360 for k, v in ipairs(data) do
361 print("", v.w)
363 assert(false)
365 assert(ept, tw)
367 while #data > ept do table.remove(data) end
369 return data
372 --[[
373 *****************************************************************
374 List-accum functions
377 function list_accumulate(item, id, inp)
378 if not inp then return end
380 if not item[id] then item[id] = {} end
381 local t = item[id]
383 if type(inp) == "table" then
384 for k, v in pairs(inp) do
385 t[v] = (t[v] or 0) + 1
387 else
388 t[inp] = (t[inp] or 0) + 1
392 function list_most_common(tbl, mv)
393 local mcv = nil
394 local mcvw = mv
395 for k, v in pairs(tbl) do
396 if not mcvw or v > mcvw then mcv, mcvw = k, v end
398 return mcv
401 --[[
402 *****************************************************************
403 Position accumulation
406 function distance(a, b)
407 local x = a.x - b.x
408 local y = a.y - b.y
409 return math.sqrt(x*x+y*y)
412 function valid_pos(ite)
413 if not ite then return end
414 if not ite.p or not ite.x or not ite.y then return end
415 if QuestHelper_ZoneLookup[ite.p][2] == 0 then return end -- this should get rid of locations showing up in "northrend" or whatever
416 return true
419 function position_accumulate(accu, tpos)
420 if not valid_pos(tpos) then return end
422 assert(tpos.priority)
424 if not accu[tpos.priority] then accu[tpos.priority] = {} end
425 accu = accu[tpos.priority] -- this is a bit grim
427 if not accu[tpos.p] then
428 accu[tpos.p] = {}
431 local conti = accu[tpos.p]
432 local closest = nil
433 local clodist = 300
434 for k, v in ipairs(conti) do
435 local cdist = distance(tpos, v)
436 if cdist < clodist then
437 clodist = cdist
438 closest = v
442 if closest then
443 closest.x = (closest.x * closest.w + tpos.x) / (closest.w + 1)
444 closest.y = (closest.y * closest.w + tpos.y) / (closest.w + 1)
445 closest.w = closest.w + 1
446 else
447 closest = {x = tpos.x, y = tpos.y, w = 1}
448 table.insert(conti, closest)
451 accu.weight = (accu.weight or 0) + 1
454 function position_has(accu)
455 for c, v in pairs(accu) do
456 return true -- ha ha
458 return false
461 function position_finalize(sacu, mostest)
462 if not position_has(sacu) then return end
464 --[[local hi = sacu[1] and sacu[1].weight or 0
465 local lo = sacu[2] and sacu[2].weight or 0]]
467 local highest = 0
468 for k, v in pairs(sacu) do
469 if mostest and k > mostest then continue end
470 highest = math.max(highest, k)
472 assert(highest > 0 or mostest)
473 if highest == 0 then return end
475 local accu = sacu[highest] -- highest priority! :D
477 local pozes = {}
478 local tw = 0
479 for p, pi in pairs(accu) do
480 if type(p) == "string" then continue end
481 for _, v in ipairs(pi) do
482 table.insert(pozes, {p = p, x = math.floor(v.x + 0.5), y = math.floor(v.y + 0.5), w = v.w})
486 if #pozes == 0 then return position_finalize(sacu, highest - 1) end
488 return weighted_concept_finalize(pozes, 0.8, 10)
491 --[[
492 *****************************************************************
493 Locale name accum functions
496 function name_accumulate(accum, name, locale)
497 if not name then return end
498 if not accum[locale] then accum[locale] = {} end
499 accum[locale][name] = (accum[locale][name] or 0) + 1
502 function name_resolve(accum)
503 local rv = {}
504 for k, v in pairs(accum) do
505 rv[k] = list_most_common(v)
507 return rv
510 --[[
511 *****************************************************************
512 Loot accumulation functions
515 local srces = {
516 eng = {},
517 mine = {},
518 herb = {},
519 skin = {},
520 open = {},
521 extract = {},
522 de = {},
523 prospect = {},
524 mill = {},
526 loot = {ignoreyesno = true},
527 loot_trivial = {ignoreyesno = true, become = "loot"},
529 rob = {ignoreyesno = true},
530 fish = {ignoreyesno = true},
533 function loot_accumulate(source, sourcetok, Output)
534 for typ, specs in pairs(srces) do
535 if not specs.ignoreyesno then
536 local yes = source[typ .. "_yes"] or 0
537 local no = source[typ .. "_no"] or 0
539 if yes + no < 10 then continue end -- DENY
541 if yes / (yes + no) < 0.95 then continue end -- DOUBLEDENY
544 -- We don't actually care about frequency at the moment, just where people tend to get it from. This works in most cases.
545 if source[typ .. "_loot"] then for k, c in pairs(source[typ .. "_loot"]) do
546 if k ~= "gold" then
547 Output(tostring(k), nil, {source = sourcetok, count = c, type = specs.become or typ}, "loot")
549 end end
552 for k, _ in pairs(source) do
553 if type(k) ~= "string" then continue end
554 local tag = k:match("([^_]+)_items")
555 assert(not tag or srces[tag])
559 --[[
560 *****************************************************************
561 Standard data accumulation functions
564 function standard_pos_accum(accum, value, lv, locale, fluff)
565 if not fluff then fluff = 0 end
566 for _, v in ipairs(value) do
567 if math.mod(#v, 11 + fluff) ~= 0 then
568 return true
572 for _, v in ipairs(value) do
573 for off = 1, #v, 11 + fluff do
574 local tite = convert_loc(slice_loc(v:sub(off, off + 10), lv), locale)
575 if tite then position_accumulate(accum.loc, tite) end
580 function standard_name_accum(accum, value)
581 for k, v in pairs(value) do
582 if type(k) == "string" then
583 local q = string.match(k, "name_(.*)")
584 if q then name_accumulate(accum, q, value.locale) end