Module:HeroListByGrowth

local p = {} local cargo = mw.ext.cargo local List = require 'Module:ListUtil' local Hash = require 'Module:HashUtil' local escq = require 'Module:EscQ'.main1 local mf = require 'Module:MF'.main1 local toboolean = require 'Module:Bool'.toboolean

-- minimum and maximum 5* stat total from growths for (growth total / 5) -- growth rate in each stat is between 10% and 80%

local generate_bsts = function (values, n)	local z = {[0] = {0, 0}}

for i = 1, n do		local z2 = {} for w, v in pairs(z) do			local lo, hi = v[1], v[2] for weight, value in pairs(values) do				local w2 = w + weight local lo2 = lo + value local hi2 = hi + value if z2[w2] then if lo2 < z2[w2][1] then z2[w2][1] = lo2 end if hi2 > z2[w2][2] then z2[w2][2] = hi2 end else z2[w2] = {lo2, hi2} end end end z = z2	end

return z end

local dump_table = function (t, i)	i = i or 10 local row = {} for k, v in Hash.sorted_pairs(t) do		row[#row + 1] = ('[%s] = %s,'):format(k, v)		if #row == i then mw.log(('\t%s'):format(table.concat(row, ' '))) row = {} end end if #row > 0 then mw.log(('\t%s'):format(table.concat(row, ' '))) end end

local show_bst_ranges = function local growths = {} for rate = 10, 80, 5 do		growths[rate] = math.floor(math.floor(rate * 114 / 100) * 39 / 100) end local bst_ranges = generate_bsts(growths, 5) local bst_lower, bst_upper = unpack(Hash.transpose(bst_ranges))

mw.log('local BST_LOWER = {') dump_table(bst_lower) mw.log('}') mw.log('') mw.log('local BST_UPPER = {') dump_table(bst_upper) mw.log('}') end

local BST_LOWER = { [50] = 20, [55] = 22, [60] = 24, [65] = 26, [70] = 28, [75] = 30, [80] = 32, [85] = 34, [90] = 36, [95] = 38,	[100] = 40, [105] = 42, [110] = 44, [115] = 46, [120] = 48, [125] = 50, [130] = 53, [135] = 55, [140] = 57, [145] = 59,	[150] = 62, [155] = 64, [160] = 66, [165] = 68, [170] = 70, [175] = 73, [180] = 75, [185] = 77, [190] = 79, [195] = 82,	[200] = 84, [205] = 86, [210] = 88, [215] = 90, [220] = 93, [225] = 95, [230] = 97, [235] = 99, [240] = 102, [245] = 104,	[250] = 106, [255] = 108, [260] = 110, [265] = 113, [270] = 115, [275] = 117, [280] = 119, [285] = 122, [290] = 124, [295] = 126,	[300] = 128, [305] = 130, [310] = 133, [315] = 135, [320] = 137, [325] = 139, [330] = 142, [335] = 144, [340] = 146, [345] = 148,	[350] = 150, [355] = 153, [360] = 155, [365] = 158, [370] = 160, [375] = 163, [380] = 165, [385] = 168, [390] = 170, [395] = 173,	[400] = 175, }

local BST_UPPER = { [50] = 20, [55] = 22, [60] = 24, [65] = 26, [70] = 29, [75] = 31, [80] = 33, [85] = 35, [90] = 38, [95] = 40,	[100] = 42, [105] = 44, [110] = 47, [115] = 49, [120] = 51, [125] = 53, [130] = 56, [135] = 58, [140] = 60, [145] = 62,	[150] = 65, [155] = 67, [160] = 69, [165] = 71, [170] = 74, [175] = 76, [180] = 78, [185] = 80, [190] = 83, [195] = 85,	[200] = 87, [205] = 89, [210] = 92, [215] = 94, [220] = 96, [225] = 98, [230] = 101, [235] = 103, [240] = 105, [245] = 107,	[250] = 110, [255] = 112, [260] = 114, [265] = 116, [270] = 118, [275] = 121, [280] = 123, [285] = 125, [290] = 127, [295] = 129,	[300] = 132, [305] = 134, [310] = 136, [315] = 138, [320] = 140, [325] = 143, [330] = 145, [335] = 147, [340] = 149, [345] = 151,	[350] = 154, [355] = 156, [360] = 158, [365] = 160, [370] = 162, [375] = 165, [380] = 167, [385] = 169, [390] = 171, [395] = 173,	[400] = 175, }

local BOOKS = 4

function p.heroChart(frame) local args = require 'Module:Arguments'.getArgs(frame) local move = args.move local ranged = toboolean(args.ranged) local physical = toboolean(args.physical) local magical = toboolean(args.magical)

local heroQuery = List.group_by(cargo.query( 'Units=U,UnitStats=US,WeaponTypes=W', "IFNULL(CONCAT(U.Name,': ',U.Title),U.Name)=Hero,U._pageName=Page,IntID,MoveType,CONCAT(Lv1HP5+Lv1Atk5+Lv1Spd5+Lv1Def5+Lv1Res5)=Base,CONCAT(HPGR3+AtkGR3+SpdGR3+DefGR3+ResGR3)=Growth", { join = 'U.WikiName=US.WikiName,U.WeaponType=W.WikiName', where = ("IFNULL(Properties__full,) NOT LIKE '%%enemy%%' AND US.WikiName IS NOT NULL AND MoveType='%s' AND W.Classes HOLDS '%s' %s"):format(			escq(move),			ranged and 'Ranged' or 'Close',			magical and "AND W.Classes__full RLIKE 'Magical'" or physical and "AND W.Classes__full RLIKE 'Physical'" or ), groupBy = 'U._pageName', orderBy = 'Base,Growth,IFNULL(IntID,9999)', limit = 5000, }), function (v)		v.Base = tonumber(v.Base)		v.Growth = tonumber(v.Growth)		v.IntID = tonumber(v.IntID)		v.Book = v.IntID and (v.IntID <= 190 and 1 or v.IntID <= 316 and 2 or v.IntID <= 453 and 3 or 4) or 0		return ('%10d;%10d;%10s;%10s'):format(v.Base + BST_LOWER[v.Growth], v.Base + BST_UPPER[v.Growth], v.Base, v.Growth)	end)

for k, v in pairs(args) do		local base, growth = mw.ustring.match(v, '^(%d+),(%d+)%%$') if growth then local joined_key = ('%10d;%10d;%10s;%10s'):format(base + BST_LOWER[growth], base + BST_UPPER[growth], base, growth) heroQuery[joined_key] = heroQuery[joined_key] or {} end end

-- Initialize the table local tbl = mw.html.create('table'):addClass('wikitable'):addClass('default'):addClass('sortable') :css('text-align', 'center'):css('margin', 'auto'):css('font-weight', '700'):css('width', '100%')

-- Add table headers tbl:tag('th'):css('width', '5%'):wikitext('Total Lv1 stats') tbl:tag('th'):css('width', '5%'):wikitext('Total growths') tbl:tag('th'):css('width', '5%'):wikitext('Lowest total Lv40 stats') tbl:tag('th'):css('width', '5%'):wikitext('Highest total Lv40 stats') tbl:tag('th'):css('width', '7%'):wikitext('Comments') for book = 1, BOOKS do		local th = tbl:tag('th'):addClass('unsortable'):css('min-width', '210px'):wikitext('Book ', book == 4 and 'IV' or ('I'):rep(book)) if book == 1 and move == 'Infantry' then th:css('width', '35%') end end

for k, vs in Hash.sorted_pairs(heroQuery) do		local bstlo, bsthi, base, growth = k:match('(%d+)%s*;%s*(%d+)%s*;%s*(%d+)%s*;%s*(%d+)') local tr = tbl:tag('tr') tr:tag('td'):wikitext(base) tr:tag('td'):wikitext(growth, '%') tr:tag('td'):wikitext(bstlo) tr:tag('td'):wikitext(bsthi) tr:tag('td'):wikitext(args[('%d,%d%%'):format(base, growth)]) local by_book = List.group_by(vs, function (v) return v.Book end) for book = 1, BOOKS do			local td = tr:tag('td') for _, v in ipairs(by_book[book] or {}) do				td:wikitext((""):format(mf(v.Page), v.Page, v.Hero or v.Page)) end end end

return tostring(tbl) end

return p