Module:Sandbox/LVL: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
-- Load Data Files | |||
local heroes_data = mw.loadJsonData("Data:HeroData.json") | |||
local items_data = mw.loadJsonData("Data:ItemData.json") | |||
-------------------------------------------------------------------------------- | |||
-- HELPER FUNCTIONS (Logic only, no Frame stuff) | |||
-------------------------------------------------------------------------------- | |||
local function get_item_bb(target_name) | |||
-- Clean whitespace | |||
target_name = mw.text.trim(target_name) | |||
if | if tonumber(target_name) then return tonumber(target_name) end | ||
for key, item in pairs(items_data) do | |||
if item["Name"] == target_name then | |||
-- Deep nested check | |||
if item["m_mapAbilityProperties"] and item["m_mapAbilityProperties"]["BuildUpPerShot"] then | |||
return tonumber(item["m_mapAbilityProperties"]["BuildUpPerShot"]["m_strValue"]) | |||
end | |||
-- Flat check | |||
if item["BuildUpPerShot"] then | |||
return tonumber(item["BuildUpPerShot"]) | |||
end | |||
end | |||
end | |||
return nil | |||
end | |||
local function get_hero_data(hero_name) | |||
hero_name = mw.text.trim(hero_name) | |||
-- Try direct Key | |||
if heroes_data[hero_name] then return heroes_data[hero_name] end | |||
-- Try "hero_" prefix | |||
if heroes_data["hero_" .. string.lower(hero_name)] then return heroes_data["hero_" .. string.lower(hero_name)] end | |||
-- Search by Name field | |||
-- | for k, v in pairs(heroes_data) do | ||
for | if v["Name"] == hero_name then return v end | ||
end | end | ||
return nil | |||
end | |||
local function calculate_bps(hero, bb) | |||
if not hero or not hero.Weapon then return 0 end | |||
local rps = tonumber(hero.Weapon.RoundsPerSecond or 0) | |||
local spin_rps = tonumber(hero.Weapon.RoundsPerSecondAtMaxSpin or 0) | |||
return | -- Handle Spin-up logic (McGinnis/Bebop) | ||
if spin_rps > 0 then rps = spin_rps end | |||
if rps == 0 then return 0 end | |||
-- Formula: 100 / (BB * (RPS + 1)) | |||
return 100 / (bb * (rps + 1)) | |||
end | end | ||
-------------------------------------------------------------------------------- | |||
-- OUTPUT GENERATORS | |||
-------------------------------------------------------------------------------- | |||
local function generate_single_value(hero_name, item_name) | |||
local hero = get_hero_data(hero_name) | |||
if not hero then return "Hero Not Found" end | |||
local bb = get_item_bb(item_name) | |||
if not bb then return "Item Not Found" end | |||
local result = calculate_bps(hero, bb) | |||
return string.format("%.1f", result) | |||
end | |||
local function generate_table(item_name, frame) | |||
local bb = get_item_bb(item_name) | |||
if not bb then return "Error: Item '" .. item_name .. "' not found." end | |||
local hero_list = {} | |||
for key, hero in pairs(heroes_data) do | |||
local is_dev = hero["InDevelopment"] == true | |||
local is_disabled = hero["IsDisabled"] == true | |||
if not is_dev and not is_disabled and hero["Weapon"] then | |||
local val = calculate_bps(hero, bb) | |||
if val > 0 then | |||
table.insert(hero_list, { | |||
name = hero["Name"], | |||
bps = val | |||
}) | |||
end | |||
end | |||
end | |||
table.sort(hero_list, function(a, b) return a.name < b.name end) | |||
local html = mw.html.create('table') | |||
html:addClass('wikitable sortable mw-collapsible') | |||
html:tag('caption'):wikitext('Buildup Per Shot: ' .. item_name) | |||
local headerRow = html:tag('tr') | |||
headerRow:tag('th'):wikitext('Hero') | |||
headerRow:tag('th'):wikitext('% per shot') | |||
for _, h in ipairs(hero_list) do | |||
local row = html:tag('tr') | |||
-- Expand HeroIcon template | |||
local icon_template = frame:expandTemplate{ title = 'HeroIcon', args = { h.name } } | |||
row:tag('td'):wikitext(icon_template) | |||
row:tag('td'):wikitext(string.format("%.1f", h.bps)) | |||
end | |||
return tostring(html) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- MAIN TRAFFIC COP | |||
-------------------------------------------------------------------------------- | |||
function p.main(frame) | |||
local args = frame:getParent().args | |||
-- If called via #invoke directly with no parent template | |||
if not args[1] and not args['item'] then args = frame.args end | |||
local arg1 = args[1] or args['hero'] | |||
local arg2 = args[2] or args['item'] | |||
-- LOGIC: | |||
-- If 2 args provided -> It's Hero + Item -> Return Single Number | |||
-- If 1 arg provided -> It's Item Only -> Return Table | |||
if arg1 and arg2 then | |||
return generate_single_value(arg1, arg2) | |||
elseif arg1 then | |||
return generate_table(arg1, frame) | |||
else | |||
return "Error: Please provide an Item Name (for table) or Hero + Item (for single stat)." | |||
end | |||
end | |||
return p | return p | ||