Module:Weapon

-- -- Used for displaying weapon stats. used by Template:Infobox_weapon -- -- Data object format: -- return { --    name        = "Name", --    type        = "", -- "primary" or "secondary" --    -- [optional]: image	= "File:Name.png", --    -- [optional]: nickname	= "", --    cost        = 0, --    ammo        = 0, --    -- [optional]: pellets     = 0, --    automatic   = false, --    damage      = 0, --    firerate    = 0, --    precision   = 0, -- 0-100 --    reload      = 0, --    scope       = false, --    releasedate = "", -- dayNum MonthLong yearLong (1 January 2000) -- } local p = {} local default_to = require('Module:Paramtest').default_to local format_num = require('Module:Number').format_num local round = require('Module:Number').round local mainonly = require('Module:Mainonly')._main local TARGET_PRECISION = 100-82; -- A chosen percent to represent a reasonable range of accuracy a skilled player could hit within every shot. local function hitChanceAtMaxDistance(pPrecision_num) return pPrecision_num == 100 and 1 or math.min(TARGET_PRECISION / (100-pPrecision_num), 1) end -- 1 is "can hit every time" local function calcDPS(pDamage_num, pFirerate_num, pPellets_num) return pDamage_num * pFirerate_num * pPellets_num end local function calcDPM(pDPS, pAmmo_num, pFireRate_num, pReload_num) local clipUsedUpTime = pAmmo_num / pFireRate_num local totalUses = 60 / ( clipUsedUpTime + pReload_num ) return totalUses * clipUsedUpTime * pDPS end local function calcTimeToDeal40Damage(pDamage_num, pAmmo_num, pPellets_num, pFirerate_num, pReload_num) local reloads = math.floor(40 / (pDamage_num * pAmmo_num * pPellets_num)) -- Reloads needed for 40 damage local reloadTime = reloads > 0 and ( (pReload_num - (1 / pFirerate_num)) * reloads ) or 0; local timeToDealFortyDamage = ( (math.ceil(40 / (pDamage_num * pPellets_num)) - 1) * (1 / pFirerate_num) ) + reloadTime return format_num(timeToDealFortyDamage, 2) .. "s" .. (reloads > 0 and "R" or "") end local function yesnoIcon(pVal_bool) if    pVal_bool == true	then return '' elseif pVal_bool == false	then return '' else						    return '?' end end

-- -- mw._loadWeaponData shortcut for loading weapon data table -- -- @param weaponName {string} Weapon to retrieve -- @return {table} Table of weapon data -- function p._loadWeaponData( weaponName ) local noError, data = pcall( mw.loadData, 'Module:Weapon/' .. weaponName ) if noError then return data end error( data ) end function p._getStats(pGet, pName) local get = pGet local weaponData = p._loadWeaponData( pName ); local name = weaponData.name local weapontype = weaponData.type local aka = weaponData.nickname local image = weaponData.image or '' local cost = weaponData.cost local ammo = weaponData.ammo local damage = weaponData.damage local firerate = weaponData.firerate local precision = weaponData.precision local reload = weaponData.reload local releasedate = weaponData.releasedate local pellets_num = weaponData.pellets or 1 local automatic_bool = weaponData.automatic local scope_bool = weaponData.scope if not get or get=='' or get=='table' then return p._getInfobox(weapontype, name, aka, image, cost, ammo, pellets_num, automatic_bool, damage, firerate, precision, reload, scope_bool, releasedate) elseif get=='row' then return p._getRow(weapontype, name, aka, image, cost, ammo, pellets_num, automatic_bool, damage, firerate, precision, reload, scope_bool, releasedate) elseif get=='statrow' then return p._getStatsRow(weapontype, name, aka, image, cost, ammo, pellets_num, automatic_bool, damage, firerate, precision, reload, scope_bool, releasedate) elseif get=='weapontype'	then return weapontype elseif get=='name'			then return name elseif get=='image'			then return image elseif get=='cost'			then return cost elseif get=='ammo'			then return ammo elseif get=='pellets'		then return pellets_num elseif get=='automatic'		then return automatic_bool elseif get=='damage'		then return damage elseif get=='firerate'		then return firerate elseif get=='precision'		then return precision elseif get=='reload'		then return reload elseif get=='scope'			then return scope_bool elseif get=='releasedate'	then return releasedate elseif get=='dps'			then return calcDPS(tonumber(damage), tonumber(firerate), pellets_num) elseif get=='dpm'			then return calcDPM(calcDPS(tonumber(damage), tonumber(firerate), pellets_num), tonumber(ammo), tonumber(firerate), tonumber(reload)) else						    return "Invalid retrieval type." end end function p._getRow(pWeapontype, pName, pAka, pImage, pCost, pAmmo, pPellets_num, pAutomatic_bool, pDamage, pFirerate, pPrecision, pReload, pScope_bool, pReleasedate) local name = pName or "NAME REQUIRED" local aka = pAka and " ("..pAka..")" or "" local image = pImage local cost = pCost or "?" if cost == 0 then cost = 'data-sort-value="0"|Free' else cost = '|'..cost end local ammo = pAmmo or "?" local pellets = pPellets_num==1 and "" or " x"..pPellets_num.." " local damage = pDamage or "?" local firerate = pFirerate or "?" local precision = pPrecision or "?" local reload = pReload or "?" local releasedate = pReleasedate or "Unknown" return '\n|-'.. '\n| style="text-align:right;" |'..image.. '\n|'..name..''..aka.. '\n| style="text-align:center;" '..cost.. '\n| style="text-align:center;" |'..ammo..pellets.. '\n| style="text-align:center;" |'..yesnoIcon(pAutomatic_bool).. '\n| style="text-align:center;" |'..damage.. '\n| style="text-align:center;" |'..firerate..' '.. '\n| style="text-align:center;" |'..precision..'%'.. '\n| style="text-align:center;" |'..reload.. (pWeapontype == "primary" and '\n| style="text-align:center;" |'..yesnoIcon(pScope_bool) or '').. '\n|'..releasedate.. '\n|-' end function p._getStatsRow(pWeapontype, pName, pAka, pImage, pCost, pAmmo, pPellets_num, pAutomatic_bool, pDamage, pFirerate, pPrecision, pReload, pScope_bool, pReleasedate) local name = pName or "NAME REQUIRED" local weapontype = pWeapontype or "?" if weapontype=="primary" then weapontype="1" elseif weapontype=="secondary" then weapontype="2" end local ammo_num = pAmmo or 0 local damage_num = pDamage or 0 local firerate_num = pFirerate or 0 local precision_num = pPrecision or 0 local reload_num = pReload or 0 local dps_short = calcDPS(damage_num, firerate_num, pPellets_num) local dps_long = calcDPM(dps_short, ammo_num, firerate_num, reload_num) / 60 local hit_chance = hitChanceAtMaxDistance(precision_num) return '\n|-'.. '\n| style="text-align:left;"  |'..name..''.. '\n| style="text-align:center;" |'..weapontype.. '\n| style="text-align:center;" |'..format_num(dps_short, 2).. '\n| style="text-align:center;" |'..format_num(dps_long, 2).. '\n| style="text-align:center;" |'..round(damage_num * ammo_num * pPellets_num, 1).. '\n| style="text-align:center;" |'..round(hit_chance, 2).. '\n| style="text-align:center;" |'..format_num(dps_short*hit_chance, 1).. '\n| style="text-align:center;" |'..format_num(dps_long*hit_chance, 1).. '\n| style="text-align:center;" |'..calcTimeToDeal40Damage(damage_num, ammo_num, pPellets_num, firerate_num, reload_num).. '\n|-' end function p._getInfobox(pWeapontype, pName, pAka, pImage, pCost, pAmmo, pPellets_num, pAutomatic_bool, pDamage, pFirerate, pPrecision, pReload, pScope_bool, pReleasedate) local weapontype = pWeapontype or "?" local weapontype_title = "Unknown / Invalid weapon type" if weapontype=="primary" then weapontype="W1" weapontype_title="Primary Weapon (Weapon 1)" elseif weapontype=="secondary" then weapontype="W2" weapontype_title="Secondary Weapon (Weapon 2)" end local name = pName or "???" local aka = pAka and " ("..pAka..")" or '' local image = pImage; local cost_text = pCost or "?" if cost_text == '0' then cost_text = 'Free' end local ammo = pAmmo or "?" local ammo_num = pAmmo or 0 local damage_num = pDamage or 0 local firerate_num = pFirerate or 0 local precision_num = pPrecision or 0 local reload_num = pReload or 0 local releasedate = pReleasedate or "Unknown" local dps_short_num = calcDPS(damage_num, firerate_num, pPellets_num) local dps_long_num = calcDPM(dps_short_num, ammo_num, firerate_num, reload_num) / 60 local hit_chance = hitChanceAtMaxDistance(precision_num) local thCss = { ["padding"]="0 8px" } local thCssSmall = { ["font-size"]="80%" } local titleAttrCss = { ["border-bottom"]="1px dotted currentColor" } local tdCss = { ["padding"]="0 8px", ["color"]="#D5D4D4", ["background"]="#222", ["border-radius"]="3px", ["border"]="1px solid #777", ["text-align"]="center" } local noDwdpsDiffCSS = hit_chance==1 and { ["opacity"]="0.25" } or {} return mw.html.create('table') :attr({["cellspacing"]="5", ["cellpadding"]="5"}) :css({["border"]="3px double #5F6165", ["background"]="#4E5549", ["width"]="100%", ["margin-bottom"]="7px"}) :tag('tr') :tag('td'):attr({["colspan"]="2"}) :css({ ["padding"]="0 8px", ["color"]="#D5D4D4", ["background"]="#222", ["border"]="1px solid #777" }) :wikitext(name..aka.." ") :tag("span"):addClass("color1") :css({["font-size"]="75%", ["padding"]="3px 5px 2px", ["border-radius"]="8px", ["cursor"]="help"}) :attr('title', weapontype_title) :wikitext(" ( "..weapontype.." ) ") :done :done :tag('th'):addClass("color1"):css(thCss):wikitext("Cost"):done :tag('td'):css(tdCss):wikitext(cost_text.." "):done :tag('th'):addClass("color1"):css(thCss):wikitext("Release Date"):done :tag('td'):css(tdCss):wikitext(releasedate):done :tag('td'):addClass("checkerboard-hover"):attr({["colspan"]="4", ["rowspan"]="2"}):css({["text-align"]="right"}):wikitext(image):done :done :tag('tr') :tag('th'):addClass("color1"):css(thCss):wikitext("Ammo"):done :tag('td'):css(tdCss):wikitext(ammo..(pPellets_num==1 and "" or " x"..pPellets_num.." ").." "):done :tag('th'):addClass("color1"):css(thCss):wikitext("Damage"):done :tag('td'):css(tdCss):wikitext(pDamage or "?"):done :tag('th'):addClass("color1"):css(thCss):wikitext("Reload"):done :tag('td'):css(tdCss):wikitext((pReload or "?").." seconds"):done :done :tag('tr') :tag('th'):addClass("color1"):css(thCss):wikitext("Fire Rate"):done :tag('td'):css(tdCss):wikitext((pFirerate or "?").." "):done :tag('th'):addClass("color1"):css(thCss):wikitext("Precision"):done :tag('td'):css(tdCss):wikitext((pPrecision or "?").."%"):done :tag('th'):addClass("color1"):css(thCss):css(thCssSmall):attr("title", "Damage Per Second, over a short period of time.") :tag("abbr"):css(titleAttrCss):wikitext("DPS (short)"):done:done :tag('td'):css(tdCss):wikitext( round(dps_short_num, 1) ):done :tag('th'):addClass("color1"):css(thCss):wikitext("Automatic"):done :tag('td'):css(tdCss):wikitext( yesnoIcon(pAutomatic_bool) ):done :tag('th'):addClass("color1"):css(thCss):wikitext("Scope"):done :tag('td'):css(tdCss):wikitext( yesnoIcon(pScope_bool) ):done :done :tag('tr') :tag('th'):addClass("color1"):css(thCss):css(thCssSmall):attr("title", "Damage Per Second, over a long period of time.") :tag("abbr"):css(titleAttrCss):wikitext("DPS (long)"):done:done :tag('td'):css(tdCss):wikitext( round(dps_long_num, 1) ):done :tag('th'):addClass("color1"):css(thCss):css(thCssSmall):css(noDwdpsDiffCSS):attr("title", "Distance Weighted Damage Per Second, over a long period of time, over long distances.") :tag("abbr"):css(titleAttrCss):wikitext("DWDPS (long)"):done:done :tag('td'):css(tdCss):css(noDwdpsDiffCSS):wikitext( round(dps_long_num*hit_chance, 1) ):done :tag('th'):addClass("color1"):css(thCss):css(thCssSmall):css(noDwdpsDiffCSS):attr("title", "Distance Weighted Damage Per Second, over a short period of time, over long distances.") :tag("abbr"):css(titleAttrCss):wikitext("DWDPS (short)"):done:done :tag('td'):css(tdCss):css(noDwdpsDiffCSS):wikitext( round(dps_short_num*hit_chance, 1) ):done :tag('th'):addClass("color1"):css(thCss):css(thCssSmall):attr("title", "The time it takes to deal 40 damage if every shot hit. \"R\" denotes a weapon that must reload at least once to deal 40 damage (reload time included).") :tag("abbr"):css(titleAttrCss):wikitext("40 Damage"):done:done :tag('td'):css(tdCss):wikitext( calcTimeToDeal40Damage(damage_num, ammo_num, pPellets_num, firerate_num, reload_num) ):done :tag('th'):addClass("color1"):css(thCss):attr("title", "Damage Per Clip, if every bullet hit; the potential total damage a clip contains.") :tag("abbr"):css(titleAttrCss):wikitext("DPC"):done:done :tag('td'):css(tdCss):wikitext( round(damage_num * ammo_num * pPellets_num, 1) ):done :done :wikitext( mainonly("") ) :done end function p.stats(frame) local args = frame.args.name and frame.args or frame:getParent.args return p._getStats( args['get'], args['name'] ) end function p.infotable(frame) local args = (frame.args[1] or frame.args["name"]) and frame.args or frame:getParent.args return p._getStats( "table", args[1] or args['name'] ) end function p.inforow(frame) local args = frame.args[1] and frame.args or frame:getParent.args return p._getStats( "row", args[1] ) end function p.statrow(frame) local args = frame.args[1] and frame.args or frame:getParent.args return p._getStats( "statrow", args[1] ) end return p