FANDOM


-- <pre>
-- 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 "<sup>R</sup>" or "")
end
 
local function yesnoIcon(pVal_bool)
	if     pVal_bool == true	then return '[[File:Yes.svg|18px|Yes]]'
	elseif pVal_bool == false	then return '[[File:No.svg|18px|No]]'
	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 '[[File:'..name..'.png]]'
	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 "<br />("..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 "<small>x"..pPellets_num.."</small>"
	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..' [[File:ShotsPerSecond.png|Shots Per Second]]'..
		'\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("<span style='display:none;'>(</span>'''"..weapontype.."'''<span style='display:none;'>)</span>")
				:done()
			:done()
 
			:tag('th'):addClass("color1"):css(thCss):wikitext("Cost"):done()
			:tag('td'):css(tdCss):wikitext(cost_text.." [[File:Potato.png|21px]]"):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 "<small>x"..pPellets_num.."</small>").." [[File:Ammo.png|21px]]"):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 "?").." [[File:ShotsPerSecond.png]]"):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("[[Category:Weapons]]") )
	: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

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.