Editing Module:Buildup

Jump to navigation Jump to search
Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision Your text
Line 7: Line 7:
-- Handles both flat numbers and lookup in the ItemData file
-- Handles both flat numbers and lookup in the ItemData file
local function get_item_bb(target_name)
local function get_item_bb(target_name)
    if target_name == nil then return nil end
if target_name == nil then return nil end
   
    -- Clean input
-- Clean input
    local clean_name = mw.text.trim(target_name)
local clean_name = mw.text.trim(target_name)
   
    -- If user input a number directly
-- If user input a number directly
    if tonumber(clean_name) then return tonumber(clean_name) end
if tonumber(clean_name) then return tonumber(clean_name) end


    -- Iterate Item Data
-- Iterate Item Data
    for key, item in pairs(items_data) do
for key, item in pairs(items_data) do
        if item["Name"] == clean_name then
if item["Name"] == clean_name then
           
            -- Valve data structure (nested)
-- Valve data structure (nested)
            if item["m_mapAbilityProperties"] and item["m_mapAbilityProperties"]["BuildUpPerShot"] then
if item["m_mapAbilityProperties"] and item["m_mapAbilityProperties"]["BuildUpPerShot"] then
                return tonumber(item["m_mapAbilityProperties"]["BuildUpPerShot"]["m_strValue"])
return tonumber(item["m_mapAbilityProperties"]["BuildUpPerShot"]["m_strValue"])
            end
end
           
            -- Flat data structure (fallback)
-- Flat data structure (fallback)
            if item["BuildUpPerShot"] then
if item["BuildUpPerShot"] then
                return tonumber(item["BuildUpPerShot"])
return tonumber(item["BuildUpPerShot"])
            end
end
        end
end
    end
end
    return nil
return nil
end
end


-- Helper to find Hero Data by name or key
-- Helper to find Hero Data by name or key
local function get_hero_data(hero_name)
local function get_hero_data(hero_name)
    if hero_name == nil then return nil end
if hero_name == nil then return nil end
   
    local clean_name = mw.text.trim(hero_name)
local clean_name = mw.text.trim(hero_name)
   
    -- Try direct Key lookup
-- Try direct Key lookup
    if heroes_data[clean_name] then return heroes_data[clean_name] end
if heroes_data[clean_name] then return heroes_data[clean_name] end
   
    -- Try adding "hero_" prefix
-- Try adding "hero_" prefix
    local key_lower = "hero_" .. string.lower(clean_name)
local key_lower = "hero_" .. string.lower(clean_name)
    if heroes_data[key_lower] then return heroes_data[key_lower] end
if heroes_data[key_lower] then return heroes_data[key_lower] end
   
    -- Search by Name field
-- Search by Name field
    for k, v in pairs(heroes_data) do
for k, v in pairs(heroes_data) do
        if v["Name"] == clean_name then return v end
if v["Name"] == clean_name then return v end
    end
end
    return nil
return nil
end
 
-- Helper: number of bullets/pellets fired per trigger pull
-- For shotguns (Abrams, etc.) this is the pellet count.
-- For burst weapons this is the burst size.
-- For normal weapons it is 1.
local function get_bullets_per_shot(hero)
    if not hero or not hero.Weapon then return 1 end
    local bps = tonumber(
        hero.Weapon.BulletsPerShot or
        hero.Weapon.PelletsPerShot or
        hero.Weapon.BulletsPerBurst or
        1
    )
    if bps == nil or bps < 1 then bps = 1 end
    return bps
end
end


-- Core calculation logic
-- Core calculation logic
-- Returns: per_bullet_bps (float), bullets_per_shot (int)
local function calculate_bps(hero, bb)
local function calculate_bps(hero, bb)
     if not hero or not hero.Weapon then return 0, 1 end
     if not hero or not hero.Weapon then return 0 end


     local rps = tonumber(hero.Weapon.RoundsPerSecond or 0)
     local rps = tonumber(hero.Weapon.RoundsPerSecond or 0)
Line 100: Line 83:
     end
     end


    -- 3. Handle Silver (Transformed) - uses base form's RPS for buildup
     if rps == 0 then return 0 end
    if hero.Name == "Silver (Transformed)" then
        rps = 1.1111  -- Base Silver's RoundsPerSecond
    end
 
     if rps == 0 then return 0, 1 end


    local bullets_per_shot = get_bullets_per_shot(hero)
     -- Formula: 100 / (BB * (RPS + 1))
 
     return 100 / (bb * (rps + 1))
     -- Original Formula: 100 / (BB * (RPS + 1))
     -- This calculates the buildup per trigger pull assuming all pellets connect
    local bps_per_shot = 100 / (bb * (rps + 1))
 
    -- Divide by bullets/pellets per shot to get the per-bullet buildup
    local bps_per_bullet = bps_per_shot / bullets_per_shot
 
    return bps_per_bullet, bullets_per_shot
end
end


--{{#invoke:Buildup|get_bps|HERO_NAME|ITEM_NAME}}
--{{#invoke:Buildup|get_bps|HERO_NAME|ITEM_NAME}}
--Returns a single float value (rounded to 1 decimal) representing buildup PER BULLET
--Returns a single float value (rounded to 1 decimal)
p.get_bps = function(frame)
p.get_bps = function(frame)
    local hero_name = frame.args[1] or frame.args['hero']
local hero_name = frame.args[1] or frame.args['hero']
    local item_name = frame.args[2] or frame.args['item']
local item_name = frame.args[2] or frame.args['item']


    local hero = get_hero_data(hero_name)
local hero = get_hero_data(hero_name)
    if not hero then return "Hero Not Found" end
if not hero then return "Hero Not Found" end


    local bb = get_item_bb(item_name)
local bb = get_item_bb(item_name)
    if not bb then return "Item Not Found" end
if not bb then return "Item Not Found" end


    local result, _ = calculate_bps(hero, bb)
local result = calculate_bps(hero, bb)
    return string.format("%.1f", result)
return string.format("%.1f", result)
end
end


--{{#invoke:Buildup|write_buildup_table|ITEM_NAME}}
--{{#invoke:Buildup|write_buildup_table|ITEM_NAME}}
--Generates a sortable wikitable for all heroes showing per-bullet buildup
--Generates a sortable wikitable for all heroes
p.write_buildup_table = function(frame)
p.write_buildup_table = function(frame)
     local item_name = frame.args[1]
     local item_name = frame.args[1]
Line 150: Line 120:
          
          
         if not is_dev and not is_disabled and hero["Weapon"] and hero["Name"] then
         if not is_dev and not is_disabled and hero["Weapon"] and hero["Name"] then
             local val, bullets_per_shot = calculate_bps(hero, bb)
             local val = calculate_bps(hero, bb)
              
              
             if val > 0 then
             if val > 0 then
                -- Shots to proc assumes every bullet in the shot connects
                 local shots = math.ceil(100 / val)
                local per_shot = val * bullets_per_shot
                 local shots = math.ceil(100 / per_shot)
                  
                  
                 table.insert(hero_list, {
                 table.insert(hero_list, {
                     name = hero["Name"],
                     name = hero["Name"],
                     bps = val,
                     bps = val,
                    bullets_per_shot = bullets_per_shot,
                     shots = shots
                     shots = shots
                 })
                 })
Line 185: Line 152:
      
      
     if item_name then
     if item_name then
         html:tag('caption'):wikitext('Buildup Per Bullet: ' .. item_name)
         html:tag('caption'):wikitext('Buildup Per Shot: ' .. item_name)
     end
     end


Line 191: Line 158:
     local headerRow = html:tag('tr')
     local headerRow = html:tag('tr')
     headerRow:tag('th'):wikitext('Hero')
     headerRow:tag('th'):wikitext('Hero')
     headerRow:tag('th'):wikitext('% per bullet')
     headerRow:tag('th'):wikitext('% per shot')
    headerRow:tag('th'):wikitext('Bullets/Shot')
     headerRow:tag('th'):wikitext('Shots to Proc')
     headerRow:tag('th'):wikitext('Shots to Proc<br/><small>(all bullets hit)</small>')


     -- Rows
     -- Rows
     for _, h in ipairs(hero_list) do
     for _, h in ipairs(hero_list) do
         local row = html:tag('tr')
         local row = html:tag('tr')
         local hero_display
         local icon_template = frame:expandTemplate{ title = 'HeroIcon', args = { h.name } }
   
        if h.name == "Silver (Transformed)" then
            -- Detect page language from subpage (e.g. /ru)
            local currentTitle = mw.title.getCurrentTitle().fullText
            local langCode = currentTitle:match("/([^/]+)$") or "en"
            local isRussian = (langCode == "ru")
       
            local displayName = isRussian and "Сильвер (Трансформация)" or "Silver (Transformed)"
            local linkTarget = isRussian and "Silver (Transformed)/ru" or "Silver (Transformed)"
          
          
            local icon_file = string.format('[[File:Silver.png|20px|link=%s]]', linkTarget)
        -- Use data-sort-value so the table sorts correctly even with the icon
            local name_link = string.format('[[%s|%s]]', linkTarget, displayName)
            hero_display = string.format(
                '<span style="white-space:nowrap;">'
                .. '<span style="position:relative; bottom:2px;">%s</span>'
                .. ' %s'
                .. '</span>',
                icon_file, name_link
            )
        else
            hero_display = frame:expandTemplate{ title = 'HeroIcon', args = { h.name } }
        end
   
         row:tag('td')
         row:tag('td')
             :attr('data-sort-value', h.name)
             :attr('data-sort-value', h.name) -- Uses the name including "The" for consistent default sort
             :wikitext(hero_display)
             :wikitext(icon_template)
   
           
         row:tag('td'):wikitext(string.format("%.1f", h.bps))
         row:tag('td'):wikitext(string.format("%.1f", h.bps))
       
        -- Show "—" for normal single-bullet weapons, the actual count for shotguns/bursts
        if h.bullets_per_shot > 1 then
            row:tag('td'):wikitext(tostring(h.bullets_per_shot))
        else
            row:tag('td'):wikitext('—')
        end
         row:tag('td'):wikitext(tostring(h.shots))
         row:tag('td'):wikitext(tostring(h.shots))
     end
     end
Line 244: Line 181:
-- Decides whether to return a single value or a full table based on arguments
-- Decides whether to return a single value or a full table based on arguments
p.main = function(frame)
p.main = function(frame)
    local args = frame:getParent().args
local args = frame:getParent().args
    -- Handle direct #invoke calls vs Template calls
-- Handle direct #invoke calls vs Template calls
    if not args[1] and not args['item'] then args = frame.args end
if not args[1] and not args['item'] then args = frame.args end


    local arg1 = args[1] or args['hero']
local arg1 = args[1] or args['hero']
    local arg2 = args[2] or args['item']
local arg2 = args[2] or args['item']


    -- If both Hero and pItem are present -> Return Single Number
-- If both Hero and Item are present -> Return Single Number
    if arg1 and arg2 then
if arg1 and arg2 then
        -- Manually setting args for the helper function to read
-- Manually setting args for the helper function to read
        frame.args = {arg1, arg2}
frame.args = {arg1, arg2}
        return p.get_bps(frame)
return p.get_bps(frame)
       
    -- If only one arg (Item) is present -> Return Table
-- If only one arg (Item) is present -> Return Table
    elseif arg1 then
elseif arg1 then
        frame.args = {arg1}
frame.args = {arg1}
        return p.write_buildup_table(frame)
return p.write_buildup_table(frame)
       
    else
else
        return "Error: Provide [Item Name] for a table, or [Hero Name] [Item Name] for a value."
return "Error: Provide [Item Name] for a table, or [Hero Name] [Item Name] for a value."
    end
end
end
end


return p
return p
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template