![]() |
Migrate your account | Wiki Discord |
---|
Module:Weapons/characteristics
Jump to navigation
Jump to search
Submodule for handling Characteristics section on weapon articles. Used mainly for advantages and disadvantages strings. See Braton#Characteristics for sample output.
Documentation
Package items
weapons/characteristics.advantages(frame)
(function)- Builds string of advantages or disadvantages of a weapon. Percentiles categorization:
- 90-100% - "Very high"
- 75-90% - "High"
- 60-75% - "Above average"
- 45-60% - Average, doesn't display anything
- 30-45% - "Below average"
- 15-30% - "Low"
- 0-15% - "Very low"
- Parameter:
frame
Frame object (table) - Returns: str preprocessed wikitext string (string)
- Created with Docbunto
See Also
Code
--- Submodule for handling Characteristics section on weapon articles.
-- Used mainly for advantages and disadvantages strings. See [[Braton#Characteristics]] for sample output.
--
-- @module weapons/characteristics
-- @alias p
-- @author [[User:FINNER]]
-- @release stable
-- @require [[Module:String]]
-- @require [[Module:Tooltips]]
-- @require [[Module:Weapons]]
-- @require [[Module:Weapons/data]]
-- @require [[Module:Weapons/ppdata]]
-- <nowiki>
local p = {}
local trim = require('Module:String').trim
local tooltip = require 'Module:Tooltips' 'Weapons' 'full'
local Weapon = require('Module:Weapons')
local ppData = mw.loadData('Module:Weapons/ppdata')
--- Builds string of weapons ranked in nth place.
-- @function behind
-- @param {table} data
-- @param {string} place
-- @param {string} slot
-- @returns {string} String of weapon names
local function behind(data, place, slot)
local weapons = {}
for _, weapDict in pairs(data) do
if weapDict.Place == place then
for _, weapName in ipairs(weapDict) do
table.insert(weapons, tooltip(weapName))
end
break
end
end
if #weapons < 3 then
return table.concat(weapons, ' and ')
end
weapons[#weapons] = 'and ' .. weapons[#weapons]
return table.concat(weapons, ', ')
end
--- Builds string of advantages or disadvantages of a weapon.
-- Percentiles categorization:
-- * 90-100% - "Very high"
-- * 75-90% - "High"
-- * 60-75% - "Above average"
-- * 45-60% - Average, doesn't display anything
-- * 30-45% - "Below average"
-- * 15-30% - "Low"
-- * 0-15% - "Very low"
-- @function p.advantages
-- @param {table} frame Frame object
-- @returns {string} str preprocessed wikitext string
function p.advantages(frame)
local args = frame.args
local name = mw.text.decode(args['Name'])
local isAdv = (not(args['Dis']) and args['Dis'] ~= '') and true or false
local weapon = Weapon._getWeapon(name)
local slot = weapon.Slot
-- Additional notes as defined by editors outside of automated stat comparison
local check = trim(args[1])
local headerText = string.format('<b>%s over other %s weapons (excluding modular weapons):</b>', (isAdv and 'Advantages' or 'Disadvantages'), slot)
-- TODO: May try to not hard code percentiles here and just fetch the percentile table from
-- [[Module:Weapons/preprocess]]
local percentileLegendSpan = mw.html.create('span')
:css('border-bottom', '2px dotted #808080')
:css('padding', '0em')
:attr('title', 'Percentiles: 0-15% = "Very low" | 15-30% = "Low" | 30-45% = "Below average" | 60-75% = "Above average" | 75-90% = "High" | 90-100% = "Very high"')
:wikitext(headerText)
local str = { tostring(percentileLegendSpan), check }
local atts, attacks, data, stats = {}, {}, {}, {}
for i, attack in ipairs(weapon.Attacks) do
local attackCharacteristics = { '*' .. attack.AttackName .. '<small> (wiki attack index ' .. i .. ')</small>' }
atts = {
CritChance = "crit chance",
CritMultiplier = "crit multiplier",
TotalDamage = "total damage",
FireRate = "fire rate",
StatusChance = "status chance",
}
if attack.Falloff or weapon.Falloff then
atts.FalloffEnd = "maximum falloff distance"
atts.FalloffRate = "active falloff slope"
end
if (weapon.Multishot and weapon.Multishot > 1) or (attack.Multishot and attack.Multishot > 1) then
atts.Multishot = "multishot"
atts.AvgCritCount = "average number of crits per shot"
atts.AvgProcCount = "average number of procs per shot"
end
if slot == 'Melee' or slot == 'Archmelee' then
atts.FireRate = "attack speed"
atts.MeleeRange = "attack range"
else
atts.Magazine = "magazine"
atts.AmmoMax = "ammo max"
atts.ReloadSpeed = "reload speed"
end
if slot ~= 'Archgun (Atmosphere)' and slot ~= 'Archmelee' and weapon.Class ~= 'Exalted Weapon' then
atts.Disposition = "disposition"
end
stats = {}
ppAttack = ppData[slot].Attacks[i] or {Top3 = {}, Percentiles = {}}
data = ppAttack.Top3
for statKey, u in pairs(data) do
if atts[statKey] then
local label = Weapon._getValue(weapon, statKey, i)
if label == nil then
error('p.advantages(frame):' .. ' label cannot be nil for key "' .. statKey .. '" and entry '.. mw.dumpObject(weapon))
end
stats[statKey] = label -- Storing stat value for later when finding out what percentile it falls under
temp = u['' .. label] -- Seeing if calculated stat matches any top 3 entries in ppData
label = Weapon._getFormattedValue(weapon, statKey, i)
if temp and temp.Place and isAdv then
if temp.Place == 'first' then
table.insert(attackCharacteristics, ('**Highest %s (%s)'):format(atts[statKey], label) )
elseif temp.Place == 'second' then
table.insert(attackCharacteristics, ('**Second highest %s (%s) behind %s'):format(atts[statKey], label, behind(u, 'first', slot) ) )
else
table.insert(attackCharacteristics, ('**Third highest %s (%s) behind %s'):format(atts[statKey], label, behind(u, 'second', slot) ) )
end
atts[statKey] = nil
end
end
end
data = ppAttack.Percentiles
for statKey, statName in pairs(atts) do
if data[statKey] then
local label
-- Label is not necessarily the same as statKey. For example, we want readers to
-- see "1.15x animation speed" instead of "1.15 attacks/sec" for the FireRate key of a melee weapon
if (statKey == 'ReloadSpeed') then
label = Weapon._getFormattedValue(weapon, 'Reload', i)
elseif (statKey == 'FireRate' and Weapon._getValue(weapon, 'IsMelee')) then
label = Weapon._getFormattedValue(weapon, 'AttackSpeed', i)
else
label = Weapon._getFormattedValue(weapon, statKey, i)
end
local statValue = stats[statKey]
if (statValue == nil) then
error('p.advantages(frame): statValue is nil, cannot compare against a nil value; must be a number value')
end
-- Data validation; ideally we should perform it at data level instead of logic level, but
-- due to how we store data on the wiki, we have limited tooling to support this (e.g. no data definition language)
for i = 1, 7, 1 do
if (data[statKey][i] == nil) then
error(mw.dumpObject(data[statKey]))
end
end
if isAdv then
if statValue > data[statKey][1] then
table.insert(attackCharacteristics, ('**Very high %s (%s)'):format(statName, label) )
elseif statValue > data[statKey][2] then
table.insert(attackCharacteristics, ('**High %s (%s)'):format(statName, label) )
elseif statValue > data[statKey][3] then
table.insert(attackCharacteristics, ('**Above average %s (%s)'):format(statName, label) )
end
else
if statValue <= data[statKey][7] then
table.insert(attackCharacteristics, ('**Very low %s (%s)'):format(statName, label) )
elseif statValue <= data[statKey][6] then
table.insert(attackCharacteristics, ('**Low %s (%s)'):format(statName, label) )
elseif statValue <= data[statKey][5] then
table.insert(attackCharacteristics, ('**Below average %s (%s)'):format(statName, label) )
end
end
end
end
-- If no distinct advantange/disadvantage is added
if (#attackCharacteristics == 1) then
table.insert(str, attackCharacteristics[1]..(isAdv and '\n**No numerical advantages.' or '\n**No numerical disadvantages.'))
else
table.insert(str, table.concat(attackCharacteristics, '\n'))
end
end
str = table.concat(str, '\n')
return frame:preprocess(str)
end
return p
Lorem ipsum dolor sit amet