update todo
[QuestHelper.git] / Development / build2 / compile_lib.lua
blob4dcff2d389fa34cde38555e014e01d72ef68c1fd
2 ll, err = package.loadlib("/nfs/build/libcompile_core.so", "init")
3 if not ll then print(err) return end
4 ll()
6 local ass = assert
7 assert = function(parm, ...)
8 if not parm then
9 ass(parm, cur_file_id(), ...) -- ASS
10 end
11 end
13 -- I don't know why print is giving me so much trouble, but it is, sooooo
14 print = function (...)
15 local pad = ""
16 for i = 1, select("#", ...) do
17 io.stdout:write(pad)
18 local tst = tostring(select(i, ...))
19 pad = (" "):rep(#tst - math.floor(#tst / 6) * 6 + 4)
20 io.stdout:write(tst)
21 end
22 io.stdout:write("\n")
23 end
26 require("luarocks.require")
27 require("persistence")
28 require("compile_chain")
29 require("compile_debug")
30 require("bit")
31 require("pluto")
32 require("gzio")
37 -- we pretend to be WoW
40 local world = {}
41 world.QuestHelper_File = {}
42 world.QuestHelper_Loadtime = {}
43 world.GetTime = function() return 0 end
44 world.QuestHelper = { Assert = function (self, ...) assert(...) end, CreateTable = function() return {} end, ReleaseTable = function() end, IsWrath32 = function () return true end }
45 world.string = string
46 world.table = table
47 world.assert = assert
48 world.bit = {mod = function(a, b) return a - math.floor(a / b) * b end, lshift = bit.lshift, rshift = bit.rshift, band = bit.band}
49 world.math = math
50 world.strbyte = string.byte
51 world.strchar = string.char
52 world.pairs = pairs
53 world.ipairs = ipairs
54 world.print = function(...) print(...) end
55 world.QH_Timeslice_Yield = function() end
56 setfenv(loadfile("../questhelper/collect_merger.lua"), world)()
57 setfenv(loadfile("../questhelper/collect_bitstream.lua"), world)()
58 setfenv(loadfile("../questhelper/collect_lzw.lua"), world)()
59 local api = {}
60 world.QH_Collect_Merger_Init(nil, api)
61 world.QH_Collect_Bitstream_Init(nil, api)
62 world.QH_Collect_LZW_Init(nil, api)
63 LZW = api.Utility_LZW
64 Merger = api.Utility_Merger
65 Bitstream = api.Utility_Bitstream
66 assert(Merger.Add)
67 end
70 local QH_IL = {}
71 local QH_ZL = {}
72 local QH_AL = {}
74 local lookups = {
75 { -- identical to 3.2
76 realnames = {
77 {"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"},
78 {"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"},
79 {"Blade's Edge Mountains", "Hellfire Peninsula", "Nagrand", "Netherstorm", "Shadowmoon Valley", "Shattrath City", "Terokkar Forest", "Zangarmarsh"},
80 {"Borean Tundra", "Crystalsong Forest", "Dalaran", "Dragonblight", "Grizzly Hills", "Howling Fjord", "Hrothgar's Landing", "Icecrown", "Sholazar Basin", "The Storm Peaks", "Wintergrasp", "Zul'Drak"},
82 mapnames = {
83 {"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"},
84 {"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"},
85 {"BladesEdgeMountains", "Hellfire", "Nagrand", "Netherstorm", "ShadowmoonValley", "ShattrathCity", "TerokkarForest", "Zangarmarsh", [0] = "Expansion01"},
86 {"BoreanTundra", "CrystalsongForest", "Dalaran", "Dragonblight", "GrizzlyHills", "HowlingFjord", "HrothgarsLanding", "IcecrownGlacier", "SholazarBasin", "TheStormPeaks", "LakeWintergrasp", "ZulDrak", [0] = "Northrend"},
88 iswrath32 = true,
89 output_id = "3.3",
93 realnames = {
94 {"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"},
95 {"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"},
96 {"Blade's Edge Mountains", "Hellfire Peninsula", "Nagrand", "Netherstorm", "Shadowmoon Valley", "Shattrath City", "Terokkar Forest", "Zangarmarsh"},
97 {"Borean Tundra", "Crystalsong Forest", "Dalaran", "Dragonblight", "Grizzly Hills", "Howling Fjord", "Hrothgar's Landing", "Icecrown", "Sholazar Basin", "The Storm Peaks", "Wintergrasp", "Zul'Drak"},
99 mapnames = {
100 {"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"},
101 {"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"},
102 {"BladesEdgeMountains", "Hellfire", "Nagrand", "Netherstorm", "ShadowmoonValley", "ShattrathCity", "TerokkarForest", "Zangarmarsh", [0] = "Expansion01"},
103 {"BoreanTundra", "CrystalsongForest", "Dalaran", "Dragonblight", "GrizzlyHills", "HowlingFjord", "HrothgarsLanding", "IcecrownGlacier", "SholazarBasin", "TheStormPeaks", "LakeWintergrasp", "ZulDrak", [0] = "Northrend"},
105 iswrath32 = true,
106 output_id = "3.2",
110 realnames = {
111 {"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"},
112 {"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"},
113 {"Blade's Edge Mountains", "Hellfire Peninsula", "Nagrand", "Netherstorm", "Shadowmoon Valley", "Shattrath City", "Terokkar Forest", "Zangarmarsh"},
114 {"Borean Tundra", "Crystalsong Forest", "Dalaran", "Dragonblight", "Grizzly Hills", "Howling Fjord", "Icecrown", "Sholazar Basin", "The Storm Peaks", "Wintergrasp", "Zul'Drak"},
116 mapnames = {
117 {"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"},
118 {"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"},
119 {"BladesEdgeMountains", "Hellfire", "Nagrand", "Netherstorm", "ShadowmoonValley", "ShattrathCity", "TerokkarForest", "Zangarmarsh", [0] = "Expansion01"},
120 {"BoreanTundra", "CrystalsongForest", "Dalaran", "Dragonblight", "GrizzlyHills", "HowlingFjord", "IcecrownGlacier", "SholazarBasin", "TheStormPeaks", "LakeWintergrasp", "ZulDrak", [0] = "Northrend"},
122 iswrath32 = false,
123 output_id = "3.1",
127 for _, lkup in ipairs(lookups) do
128 local world = {}
129 local cropy = {
130 "string",
131 "tonumber",
132 "print",
133 "setmetatable",
134 "type",
135 "table",
136 "tostring",
137 "error",
138 "math",
139 "coroutine",
140 "pairs",
141 "ipairs",
142 "select",
144 for _, v in ipairs(cropy) do
145 world[v] = _G[v]
147 world.getfenv = function (x) assert(x == 0 or not x) return world end
150 world._G = world
151 world.GetPlayerFacing = function () return 0 end
152 world.MinimapCompassTexture = {GetTexCoord = function() return 0, 1 end}
153 world.CreateFrame = function () return {Hide = function () end, SetParent = function () end, UnregisterAllEvents = function () end, RegisterEvent = function () end, SetScript = function () end} end
154 world.GetMapContinents = function () return "Kalimdor", "Eastern Kingdoms", "Outland", "Northrend" end
155 world.GetMapZones = function (z)
156 local db = lkup.realnames
157 return unpack(db[z])
160 local tc, tz
161 world.SetMapZoom = function (c, z) tc, tz = c, z end
162 world.GetMapInfo = function ()
163 return lkup.mapnames[tc][tz]
165 world.IsLoggedIn = function () end
167 world.QuestHelper_File = {}
168 world.QuestHelper_Loadtime = {}
169 world.GetTime = function() return 0 end
170 world.QuestHelper = { Assert = function (self, ...) assert(...) end, CreateTable = function() return {} end, ReleaseTable = function() end, TextOut = function(qh, ...) print(...) end, IsWrath32 = function () return lkup.iswrath32 end }
172 setfenv(loadfile("../questhelper/AstrolabeQH/DongleStub.lua"), world)()
173 setfenv(loadfile("../questhelper/AstrolabeQH/AstrolabeMapMonitor.lua"), world)()
174 setfenv(loadfile("../questhelper/AstrolabeQH/Astrolabe.lua"), world)()
175 setfenv(loadfile("../questhelper/upgrade.lua"), world)()
177 world.QuestHelper.Astrolabe = world.DongleStub("Astrolabe-0.4-QuestHelper")
178 QH_AL[lkup.output_id] = world.QuestHelper.Astrolabe
179 assert(QH_AL[lkup.output_id])
181 world.QuestHelper_BuildZoneLookup()
183 QH_IL[lkup.output_id] = world.QuestHelper_IndexLookup
184 QH_ZL[lkup.output_id] = world.QuestHelper_ZoneLookup
188 local function get_index(v)
189 assert(v)
190 if v == "0.1.0" then return "3.1" end
191 if v == "0.2.0" then return "3.2" end
192 if v == "0.3.0" then return "3.3" end
193 if version_lessthan(v, "3.0.0") then print("Unknown version - ", v) assert(false) end
194 if version_lessthan(v, "3.2.0") then return "3.1" end
195 if v == "3.2.0" or v == "3.2.2" then return "3.2" end
196 if v == "3.3.0" or v == "3.3.2" or v == "3.3.3" then return "3.3" end
197 print("invalid version", v)
198 assert(false, v)
201 function QuestHelper_IndexLookup(v)
202 return QH_IL[get_index(v)]
204 function QuestHelper_ZoneLookup(v)
205 return QH_ZL[get_index(v)]
207 function Astrolabe(v)
208 return QH_AL[get_index(v)]
211 -- LuaSrcDiet embedding
213 local world = {arg = {}}
214 world.string = string
215 world.table = table
216 world.pcall = pcall
217 world.print = print
218 world.ipairs = ipairs
219 world.TEST = true
220 setfenv(loadfile("LuaSrcDiet.lua"), world)()
221 world.TEST = false
222 world.error = error
223 world.tonumber = tonumber
225 local files = {input = {}, output = {}}
227 local function readgeneral(target)
228 local rv = target[target.cline]
229 target.cline = target.cline + 1
230 return rv
233 world.io = {
234 open = function(fname, typ)
235 if fname == "input" then
236 assert(typ == "rb")
237 return {
238 read = function(_, wut)
239 assert(wut == "*l")
240 return readgeneral(files.input)
241 end,
242 close = function() end
244 elseif fname == "output" then
246 if typ == "wb" then
247 return {
248 write = function(_, wut, nilo)
249 assert(not nilo)
250 assert(not files.output_beta)
251 Merger.Add(files.output, wut)
252 end,
253 close = function() end
255 elseif typ == "rb" then
256 files.output_beta = {}
257 for k in Merger.Finish(files.output):gmatch("[^\n]*") do
258 table.insert(files.output_beta, k)
260 files.output_beta.cline = 1
262 return {
263 read = function(_, wut)
264 assert(wut == "*l")
265 return readgeneral(files.output_beta)
266 end,
267 close = function() end
269 else
270 assert()
274 end,
275 close = function() end,
276 stdout = io.stdout,
279 Diet = function(inp)
280 world.arg = {"input", "-o", "output", "--quiet", "--maximum"}
281 files.input = {}
282 for k in inp:gmatch("[^\n]*") do
283 table.insert(files.input, k)
285 files.input.cline = 1
286 files.output = {}
287 files.output_beta = nil
289 local ok = pcall(world.main)
290 if not ok then return end
292 return Merger.Finish(files.output)
295 --assert(Diet(" q = 15 ") == "q=15")
296 --assert(Diet(" jbx = 15 ") == "jbx=15")
297 --return
301 ChainBlock_Init("/nfs/build", "compile.lua", function ()
302 os.execute("rm -rf intermed")
303 os.execute("mkdir intermed")
305 os.execute("rm -rf final")
306 os.execute("mkdir final") end, ...)
308 math.umod = function (val, med)
309 if val < 0 then
310 return math.mod(val + math.ceil(-val / med + 10) * med, med)
311 else
312 return math.mod(val, med)
316 zone_image_chunksize = 1024
317 zone_image_descale = 4
318 zone_image_outchunk = zone_image_chunksize / zone_image_descale
320 zonecolors = {}
322 --[[
323 *****************************************************************
324 Utility functions
327 function version_parse(x)
328 if not x then return end
330 local rv = {}
331 for t in x:gmatch("[%d]+") do
332 table.insert(rv, tonumber(t))
334 return rv
337 -- sortversion(a,b) is equivalent to a>b
338 function sortversion(a, b)
339 local ap, bp = version_parse(a), version_parse(b)
340 if not ap and not bp then return false end
341 if not ap then return false end
342 if not bp then return true end
343 for x = 1, #ap do
344 if ap[x] ~= bp[x] then
345 return (ap[x] or -1000) > (bp[x] or -1000)
348 return false
350 function version_lessthan(a, b) -- sigh
351 return sortversion(b, a)
354 function tablesize(tab)
355 local ct = 0
356 for _, _ in pairs(tab) do
357 ct = ct + 1
359 return ct
362 function loc_version(ver)
363 local major = ver:match("([0-9])%..*")
364 if version_lessthan(major, "0.77") then
365 return 0
366 elseif version_lessthan(major, "0.96") then
367 return 1
368 elseif version_lessthan(major, "1.0.0") then
369 return 2
370 elseif version_lessthan(major, "1.0.2") then
371 return 1
372 elseif version_lessthan(major, "2.0.0") then
373 return 2
374 else
375 assert()
379 function convert_loc(loc, locale, lv, wowv)
380 if not loc then return end
381 assert(locale)
382 if locale ~= "enUS" then --[[print"dropout enUS"]] loc.x = nil loc.y = nil return end -- arrrgh, to be fixed eventually. the problem is that .rc and .rz change based on the locale, so I need to snapshot conversions for all locales :(
384 local lr = loc.relative
385 if loc.relative then
386 loc.c, loc.x, loc.y = Astrolabe(wowv):GetAbsoluteContinentPosition(loc.rc, loc.rz, loc.x, loc.y)
387 loc.relative = false
390 if not loc.c or not QuestHelper_IndexLookup(wowv)[loc.rc] then return end
392 if not QuestHelper_IndexLookup(wowv)[loc.rc] or not QuestHelper_IndexLookup(wowv)[loc.rc][loc.rz] then
393 --print(loc.c, loc.rc, loc.rz, QuestHelper_IndexLookup(wowv), QuestHelper_IndexLookup(wowv)[loc.rc])
394 --print(loc.c, loc.rc, loc.rz, QuestHelper_IndexLookup(wowv), QuestHelper_IndexLookup(wowv)[loc.rc], QuestHelper_IndexLookup(wowv)[loc.rc][loc.rz])
396 loc.p = QuestHelper_IndexLookup(wowv)[loc.rc][loc.rz]
397 loc.rc, loc.rz = nil, nil
399 if lv == 0 and loc.p == 71 then --[[print"dropout old icecrown"]] loc.x = nil loc.y = nil return end -- Icecrown, which I had offsync for a while
401 if loc.x < -100000 or loc.x > 100000 or loc.y < -100000 or loc.y > 100000 then --[[print("dropout oob", loc.x, loc.y) ]]return end -- out-of-bounds, nothing like this actually exists
403 --[[print"accept" ]]
405 return loc
408 function convert_multiple_loc(locs, locale, lv, wowv)
409 if not locs then return end
411 local locrv = {}
413 for _, v in ipairs(locs) do
414 if v.loc then
415 local cl = convert_loc(v.loc, locale, lv, wowv)
416 if cl then table.insert(locrv, v) end -- note, we are not inserting cl, we're inserting v - it may contain more info
420 local st = #locs
421 while #locs > 0 do table.remove(locs) end
422 for _, v in ipairs(locrv) do table.insert(locs, v) end
423 --print(st, #locs)
426 --[[
427 *****************************************************************
428 Weighted multi-concept accumulation
431 function weighted_concept_finalize(data, fraction, minimum, total_needed)
432 if #data == 0 then return end
434 fraction = fraction or 0.9
435 minimum = minimum or 1
437 table.sort(data, function (a, b) return a.w > b.w end)
439 local tw = total_needed
440 if not tw then
441 tw = 0
442 for _, v in ipairs(data) do
443 tw = tw + v.w
447 local ept
448 local wacu = 0
449 for k, v in ipairs(data) do
450 wacu = wacu + v.w
451 v.w = nil
452 if wacu >= tw * fraction or (data[k + 1] and data[k + 1].w < minimum) or not data[k + 1] then
453 ept = k
454 break
458 if not ept then
459 print(total_needed)
460 for k, v in ipairs(data) do
461 print("", v.w)
463 assert(false)
465 assert(ept, tw)
467 while #data > ept do table.remove(data) end
469 return data
472 --[[
473 *****************************************************************
474 List-accum functions
477 function list_accumulate(item, id, inp)
478 if not inp then return end
480 if not item[id] then item[id] = {} end
482 list_accumulate_item(item[id], inp)
485 function list_accumulate_item(item, inp)
486 local t = item
488 if type(inp) == "table" then
489 for k, v in pairs(inp) do
490 t[v] = (t[v] or 0) + 1
492 else
493 t[inp] = (t[inp] or 0) + 1
497 function list_most_common(tbl, mv)
498 if not tbl then return nil end
500 local mcv = nil
501 local mcvw = mv
502 for k, v in pairs(tbl) do
503 if not mcvw or v > mcvw then mcv, mcvw = k, v end
505 return mcv
508 --[[
509 *****************************************************************
510 Solids accumulation
513 solid_grid = 16
515 function solids_accumulate(accu, tpos)
516 if not accu[tpos.c] then accu[tpos.c] = {} end
517 local lex, ley = math.floor(tpos.x / solid_grid), math.floor(tpos.y / solid_grid)
518 if not accu[tpos.c][lex] then accu[tpos.c][lex] = {} end
519 accu[tpos.c][lex][ley] = (accu[tpos.c][lex][ley] or 0) + 1
521 function solids_combine(dest, src)
522 for k, v in pairs(src) do
523 if not dest[k] then dest[k] = {} end
524 for x, tv in pairs(v) do
525 if not dest[k][x] then dest[k][x] = {} end
526 for y, ttv in pairs(tv) do
527 dest[k][x][y] = (dest[k][x][y] or 0) + ttv
533 --[[
534 *****************************************************************
535 Position accumulation
538 function distance(a, b)
539 local x = a.x - b.x
540 local y = a.y - b.y
541 return math.sqrt(x*x+y*y)
544 function valid_pos(ite, wowv)
545 if not ite then return end
546 if not ite.p or not ite.x or not ite.y then return end
547 if QuestHelper_ZoneLookup(wowv)[ite.p][2] == 0 then return end -- this should get rid of locations showing up in "northrend" or whatever
548 return true
551 function position_accumulate(accu, tpos, wowv)
552 if not valid_pos(tpos, wowv) then return end
554 assert(tpos.priority)
556 if not accu[tpos.priority] then accu[tpos.priority] = {solid = {}} end
557 accu = accu[tpos.priority] -- this is a bit grim
559 if not accu[tpos.p] then
560 accu[tpos.p] = {}
563 accu["wowv_" .. wowv] = (accu["wowv_" .. wowv] or 0) + 1
565 local conti = accu[tpos.p]
566 local closest = nil
567 local clodist = 300
568 for k, v in ipairs(conti) do
569 local cdist = distance(tpos, v)
570 if cdist < clodist then
571 clodist = cdist
572 closest = v
576 if closest then
577 closest.x = (closest.x * closest.w + tpos.x) / (closest.w + 1)
578 closest.y = (closest.y * closest.w + tpos.y) / (closest.w + 1)
579 closest.w = closest.w + 1
580 else
581 closest = {x = tpos.x, y = tpos.y, w = 1}
582 table.insert(conti, closest)
585 accu.weight = (accu.weight or 0) + 1
587 solids_accumulate(accu.solid, tpos)
590 function position_has(accu)
591 for c, v in pairs(accu) do
592 return true -- ha ha
594 return false
597 function position_finalize(sacu, mostest)
598 if not position_has(sacu) then return end
600 --[[local hi = sacu[1] and sacu[1].weight or 0
601 local lo = sacu[2] and sacu[2].weight or 0]]
603 local highest = 0
604 for k, v in pairs(sacu) do
605 if mostest and k > mostest then continue end
606 highest = math.max(highest, k)
608 assert(highest > 0 or mostest)
609 if highest == 0 then return end
611 local accu = sacu[highest] -- highest priority! :D
613 local pozes = {}
614 local tw = 0
615 for p, pi in pairs(accu) do
616 if type(p) == "string" then continue end
617 for _, v in ipairs(pi) do
618 table.insert(pozes, {p = p, x = math.floor(v.x + 0.5), y = math.floor(v.y + 0.5), w = v.w})
622 if #pozes == 0 then return position_finalize(sacu, highest - 1) end
624 local rv = weighted_concept_finalize(pozes, 0.8, 10)
625 rv.solid = accu.solid
626 if dbg_data then
627 for k, v in pairs(accu) do
628 if type(k) == "string" then
629 rv[k] = v
633 return rv
636 --[[
637 *****************************************************************
638 Locale name accum functions
641 function name_accumulate(accum, name, locale)
642 if not name then return end
643 if not accum[locale] then accum[locale] = {} end
644 accum[locale][name] = (accum[locale][name] or 0) + 1
647 function name_resolve(accum)
648 local rv = {}
649 for k, v in pairs(accum) do
650 rv[k] = list_most_common(v)
652 return rv
655 --[[
656 *****************************************************************
657 Loot accumulation functions
660 local srces = {
661 eng = {},
662 mine = {},
663 herb = {},
664 skin = {},
665 open = {},
666 extract = {},
667 de = {},
668 prospect = {},
669 mill = {},
671 loot = {ignoreyesno = true},
672 loot_trivial = {ignoreyesno = true, become = "loot"},
674 rob = {ignoreyesno = true},
675 fish = {ignoreyesno = true},
678 function loot_accumulate(source, sourcetok, Output)
679 for typ, specs in pairs(srces) do
680 if not specs.ignoreyesno then
681 local yes = source[typ .. "_yes"] or 0
682 local no = source[typ .. "_no"] or 0
684 if yes + no < 10 then continue end -- DENY
686 if yes / (yes + no) < 0.95 then continue end -- DOUBLEDENY
689 -- We don't actually care about frequency at the moment, just where people tend to get it from. This works in most cases.
690 if source[typ .. "_loot"] then
691 for k, c in pairs(source[typ .. "_loot"]) do
692 if k ~= "gold" then
693 Output(tostring(k), nil, {source = sourcetok, count = c, type = specs.become or typ}, "loot")
699 for k, _ in pairs(source) do
700 if type(k) ~= "string" then continue end
701 local tag = k:match("([^_]+)_items")
702 assert(not tag or srces[tag])
706 --[[
707 *****************************************************************
708 Standard data accumulation functions
711 function standard_pos_accum(accum, value, lv, locale, fluff, wowv)
712 assert(locale)
713 if not fluff then fluff = 0 end
715 -- bleh
716 if type(value) == "string" then
717 if math.mod(#value, 11 + fluff) ~= 0 then return true end
718 --print("SPA start")
719 for off = 1, #value, 11 + fluff do
720 local tite = convert_loc(slice_loc(value:sub(off, off + 10), lv), locale, lv, wowv)
721 if tite then position_accumulate(accum.loc, tite, wowv) end
723 --if tite then print("Y") else print(".") end
725 --print("SPA end")
726 else
727 for _, v in ipairs(value) do
728 if math.mod(#v, 11 + fluff) ~= 0 then
729 return true
733 --print("SPA start")
734 for _, v in ipairs(value) do
735 for off = 1, #v, 11 + fluff do
736 local tite = convert_loc(slice_loc(v:sub(off, off + 10), lv), locale, lv, wowv)
737 if tite then position_accumulate(accum.loc, tite, wowv) end
739 --if tite then print("Y") else print(".") end
742 --print("SPA end")
746 function standard_name_accum(accum, value)
747 for k, v in pairs(value) do
748 if type(k) == "string" then
749 local q = string.match(k, "name_(.*)")
750 if q then name_accumulate(accum, q, value.locale) end