FANDOM


--This will eventually contain data for various weapons
--For use in automating assorted wiki functions and to reduce the number of updates needed
--But starting with Melee Stances
 
local p = {}
 
local WeaponData = mw.loadData( 'Module:Weapons/data' )
local Icon = require( "Module:Icon" )
local Shared = require( "Module:Shared" )
local Elements = {"Impact", "Puncture", "Slash", "Heat", "Cold", "Toxin", "Electricity", "Blast", "Corrosive", "Radiation", "Magnetic", "Gas", "Viral"}
local Physical = {"Impact", "Puncture", "Slash"}
local UseDefaultList = {"NOISELEVEL", "AMMOTYPE", "MAXAMMO", "DISPOSITION"}
 
function p.doPlural(Text, Value)
    if(tonumber(Value) == 1) then
        Text = string.gsub(Text, "(<.+>)", "")
    else
        Text = string.gsub(Text, "<(.+)>", "%1")
    end
    return Text
end
 
function p.getWeapon(WeapName)
    for key, Weapon in Shared.skpairs(WeaponData["Weapons"]) do
        if(Weapon.Name == WeapName or key == WeapName) then
            return Weapon            
        end
    end
    return nil
end
 
function p.isMelee(frame)
    if(frame == nil) then
        return nil
    end
    local Weapon = frame.args ~= nil and frame.args[1] or frame
    if(type(Weapon) == "string") then
        Weapon = p.getWeapon(Weapon)
    end
 
    if(Weapon == nil) then
        return nil
    end
 
    if(Weapon.Type ~= nil and (Weapon.Type == "Melee" or Weapon.Type == "Arch-Melee")) then
        return "yes"
    end
 
    return nil
end
 
local function getAttack(Weapon, AttackType)
    if(Weapon == nil or AttackType == nil) then
        return nil
    elseif(type(Weapon) == "string") then
        Weapon = p.getWeapon(Weapon)
    end
    AttackType = string.upper(AttackType)
    if (AttackType == nil or AttackType == "NORMAL" or AttackType == "NORMALATTACK") then
        if(Weapon.Damage ~= nil) then return Weapon else return nil end
    elseif(AttackType == "CHARGE" or AttackType == "CHARGEATTACK") then
        return Weapon.ChargeAttack
    elseif(AttackType == "AREA" or AttackType == "AREAATTACK") then
        return Weapon.AreaAttack
    elseif(AttackType == "SECONDARYAREA" or AttackType == "SECONDARYAREAATTACK") then
        return Weapon.SecondaryAreaAttack
    elseif(AttackType == "THROW" or AttackType == "THROWATTACK") then
        return Weapon.ThrowAttack
    elseif(AttackType == "CHARGEDTHROW" or AttackType == "CHARGEDTHROWATTACK") then
        return Weapon.ChargedThrowAttack
    elseif(AttackType == "SECONDARY" or AttackType == "SECONDARYATTACK") then
        return Weapon.SecondaryAttack
    else
        return nil
    end
end
 
local function hasAttack(Weapon, AttackType)
    if(getAttack(Weapon, AttackType) ~= nil) then return "yes" else return nil end
end
 
function p.hasAttack(frame)
    local WeapName = frame.args[1]
    local AttackName = frame.args[2]
 
    if(WeapName == nil) then
        return "ERROR: No weapon name"
    elseif(AttackName == nil) then
        AttackName = "Normal"
    end
 
    local Weapon = p.getWeapon(WeapName)
    if(Weapon == nil) then return "ERROR: No weapon "..WeapName.." found" end
 
    return hasAttack(Weapon, AttackName)
end
 
function hasMultipleTypes(Attack)
    local typeCount = 0
    if(Attack ~= nil and Attack.Damage ~= nil) then
        for key, dmg in Shared.skpairs(Attack.Damage) do
            if(dmg > 0) then
                typeCount = typeCount + 1
            end
        end
    end
    if(typeCount > 1) then return "yes" else return nil end
end
 
function p.hasMultipleTypes(frame)
    local WeapName = frame.args[1]
    local AttackName = frame.args[2]
    if(AttackName == nil) then AttackName = "Normal" end
    local attack = getAttack(WeapName, AttackName)
    return hasMultipleTypes(attack)
end
 
function p.attackLoop(Weapon)
    if(Weapon == nil) then
        return function() return nil end
    end
    local aType = "Normal"
    local iterator = function()
            if(aType == "Normal") then
                local attack = getAttack(Weapon, aType)
                aType = "Charge"
                if attack ~= nil and attack.Damage ~= nil then return "Normal", attack end
            end
            if(aType == "Charge") then
                local attack = getAttack(Weapon, aType)
                aType = "Area"
                if attack ~= nil and attack.Damage ~= nil then return "Charge", attack end
            end
            if(aType == "Area") then
                local attack = getAttack(Weapon, aType)
                aType = "SecondaryArea"
                if attack ~= nil and attack.Damage ~= nil then return "Area", attack end
            end
            if(aType == "SecondaryArea") then
                local attack = getAttack(Weapon, aType)
                aType = "Secondary"
                if attack ~= nil and attack.Damage ~= nil then return "SecondaryArea", attack end
            end
            if(aType == "Secondary") then
                local attack = getAttack(Weapon, aType)
                aType = "Throw"
                if attack ~= nil and attack.Damage ~= nil then return "Secondary", attack end
            end
            if(aType == "Throw") then
                local attack = getAttack(Weapon, aType)
                aType = "ChargedThrow"
                if attack ~= nil and attack.Damage ~= nil then return "Throw", attack end
            end
            if(aType == "ChargedThrow") then
                local attack = getAttack(Weapon, aType)
                aType = "end"
                if attack ~= nil and attack.Damage ~= nil then return "ChargedThrow", attack end
            end
 
            return nil
        end
    return iterator
end
 
function p.getStance(StanceName)
    for i, Stance in pairs(WeaponData["Stances"]) do
        if(Stance.Name == StanceName) then
            return Stance
        end
    end
    return nil
end
 
local function getAugments(Weapon)
    local name = Weapon.Name ~= nil and Weapon.Name or Weapon
    local augments = {}
    for i, Augment in pairs(WeaponData["Augments"]) do
        for j, WeapName in pairs(Augment.Weapons) do
            if(WeapName == name) then
                table.insert(augments, Augment)
            end
        end
    end
    return augments
end
 
local function getFamily(FamilyName)
    local familyMembers = {}
    for i, Weapon in Shared.skpairs(WeaponData["Weapons"]) do
        if(Weapon.Family == FamilyName) then
            table.insert(familyMembers, Weapon)
        end
    end
    return familyMembers
end
 
local function linkMeleeClass(weapClass)
    if(weapClass == nil) then
        return nil
    else
        return "[[:Category:"..weapClass.."|"..weapClass.."]]"
    end
end
 
--Returns all melee weapons.
--If weapType is not nil, only grab for a specific type
--For example, if weapType is "Nikana", only pull Nikanas
local function getMeleeWeapons(weapClass, PvP)
    local weaps = {}
    local weapClasses = {}
    if(weapClass ~= nil) then
        weapClasses = Shared.splitString(weapClass, ',')
    end
 
    for i, weap in Shared.skpairs(WeaponData["Weapons"]) do
        if(p.isMelee(weap)) then
            local classMatch = (weapClass == nil or Shared.contains(weapClasses, weap.Class))
            local pvpMatch = (PvP == nil or (PvP and weap.Conclave ~= nil and weap.Conclave))
            if (classMatch and pvpMatch) then
                table.insert(weaps, weap)
            end
        end
    end
 
    return weaps
end
 
--Learning new things... Trying to allow sending in an arbitrary function
local function getWeapons(validateFunction)
    local weaps = {}
    for i, weap in Shared.skpairs(WeaponData["Weapons"]) do
        if(validateFunction(weap)) then
            table.insert(weaps, weap)
        end
    end
    return weaps
end
 
local function asPercent(val, digits)
    if(digits == nil) then digits = 2 end
    if(val == nil) then val = 0 end
    local result = val * 100
    return Shared.round(result, digits).."%"
end
 
local function asMultiplier(val)
    if(val == nil) then
        return "1.0x"
    end
    return Shared.round(val, 2, 1).."x"
end
 
--Returns all melee weapons.
--If weapType is not nil, only grab for a specific type
--For example, if weapType is "Nikana", only pull Nikanas
local function getStances(weapType, pvpOnly)
    local stances = {}
 
    for i, stance in Shared.skpairs(WeaponData["Stances"]) do
        local classMatch = (weapType == nil or weapType == stance.Class)
        local pvpMatch = (pvpOnly ~= nil and pvpOnly) or (stance.PvP == nil or not stance.PvP)
        if (classMatch and pvpMatch) then
            table.insert(stances, stance)
        end
    end
 
    return stances
end
 
local function HasTrait(Weapon, Trait)
    if(Trait == nil or Weapon.Traits == nil) then
        return false
    end
 
    for i, theTrait in pairs(Weapon.Traits) do
        if(theTrait == Trait) then
            return true
        end
    end
 
    return false
end
 
--If Type is not nil, get damage weapon deals of that type
--If it deals no damage of that type, return 0 instead of nil
--It Type is nil, return total damage
local function GetDamage(Weapon, Type)
    if(Type == nil) then
        local total = 0
            for i, d in Shared.skpairs(Weapon.Damage) do
                total = total + d
            end
        return total
    else
        if(Type == "Physical") then
            local Impact = Weapon.Damage["Impact"] ~= nil and Weapon.Damage["Impact"] or 0
            local Puncture = Weapon.Damage["Puncture"] ~= nil and Weapon.Damage["Puncture"] or 0
            local Slash = Weapon.Damage["Slash"] ~= nil and Weapon.Damage["Slash"] or 0
            return Impact + Puncture + Slash
        elseif(Type == "Element") then
            for dType, dmg in Shared.skpairs(Weapon.Damage) do
                if(not Shared.contains(Physical, dType) or dmg <= 0) then
                    return dmg
                end
            end
            return 0
        elseif(Weapon.Damage[Type] == nil) then
            return 0
        else
            return Weapon.Damage[Type]
        end
    end
end
 
--Returns the damage string as it's formatted in a comparison row
--So instead of '0', returns '-', and appends the icon for an element if necessary
local function GetDamageString(Weapon, Type, includeText)
    if(Type == nil) then
        if(Shared.tableCount(Weapon.Damage) == 1) then
            for key, val in pairs(Weapon.Damage) do
                return Icon._Proc(key, includeText).." "..Shared.round(val, 2)
            end
        else
            return Shared.round(GetDamage(Weapon), {2, 1})
        end
    else
        local thisVal = GetDamage(Weapon, Type)
        if(thisVal == 0) then
            return ""
        else
            return Shared.round(thisVal, {2, 1})
        end
    end
end
 
local function GetDamageBias(Attack)
    if(Attack.Damage ~= nil and Shared.tableCount(Attack.Damage) > 1) then
        local total = 0
        local bestDmg = 0
        local bestElement = nil
        local count = 0
        for Element, Dmg in pairs(Attack.Damage) do
            if(Dmg > bestDmg) then
                bestDmg = Dmg
                bestElement = Element
            end
            total = total + Dmg
            if(Dmg > 0) then
                count = count + 1
            end
        end
        --Make sure there are two damage instances that are above zero
        if(count > 1) then
            return (bestDmg / total), bestElement
        else
            return nil
        end
    else
        return nil
    end
end
 
--If the attack has at least two damage types,
--  Returns something like "58.3% Slash"
--If it doesn't, returns nil
local function GetDamageBiasString(Attack, hideType, showText)
    if(showText == nil) then showText = "text" end
    local bestPercent, bestElement = GetDamageBias(Attack, hideType)
    if(bestPercent ~= nil) then
        local result = asPercent(bestPercent, 0)
        if(hideType == nil or not hideType) then
            result = Icon._Proc(bestElement, showText).." "..result
        end
        return result
    else
        return nil
    end
end
 
local function GetPolarityString(Weapon)
    if(Weapon.Polarities == nil or Shared.tableCount(Weapon.Polarities) == 0) then
        return "None"
    else
        local resString = ""
        for i, pol in pairs(Weapon.Polarities) do
            resString = resString..Icon._Pol(pol)
        end
        return resString
    end
end
 
local function GetStancePolarity(Weapon)
    if(Weapon.StancePolarity == nil or Weapon.StancePolarity == "None") then
        return "None"
    else
        return Icon._Pol(Weapon.StancePolarity)
    end
end
 
local function getWeaponStanceList(Weapon)
    local stances = getStances(Weapon.Class, Weapon.Conclave)
 
    local result = ""
 
    for i, stance in pairs(stances) do
        if (string.len(result) > 0) then
            result = result.."<br/>"
        end
 
        result = result.."[["..stance.Name.."]]".." ("..Icon._Pol(stance.Polarity)..")"
        --If this is a PvP Stance, add the disclaimer
        if(stance.PvP ~= nil and stance.PvP) then
            result = result.." (PvP Only)"
        end
    end
 
    return result
end
 
local function getAttackValue(Weapon, Attack, ValName, giveDefault, asString)
    if(giveDefault == nil) then giveDefault = false end
    if(asString == nil) then asString = false end
    if(Attack == nil) then 
        if(asString) then
            return ""
        else
            return nil 
        end
    end
    regularVal = Shared.titleCase(string.sub(ValName, 1, 1), string.sub(ValName, 2))
    ValName = string.upper(ValName)
    if(ValName == "DAMAGE") then
        if(Attack.Damage ~= nil) then
            if(asString) then
                return GetDamageString(Attack, nil)
            else
                return GetDamage(Attack)
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "DAMAGEPLUS") then
        if(Attack.Damage ~= nil) then
            if(asString) then
                if(hasMultipleTypes(Attack)) then
                    return GetDamageString(Attack, nil).." ("..GetDamageBiasString(Attack, nil, "")..")"
                else
                    return GetDamageString(Attack, nil)
                end
            else
                return GetDamage(Attack)
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(Shared.contains(Elements, regularVal) or ValName == "PHYSICAL" or ValName == "ELEMENT") then
        if(Attack.Damage ~= nil) then
            if(asString) then
                if(hasMultipleTypes(Attack)) then
                    return GetDamageString(Attack,  regularVal)
                else
                    return nil
                end
            else
                return GetDamage(Attack,  regularVal)
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "ATTACKNAME") then
        if(Attack.AttackName ~= nil) then
            return Attack.AttackName
        elseif(giveDefault) then
            return ""
        else
            return nil
        end
    elseif(ValName == "BURSTCOUNT") then
        if(Attack.BurstCount ~= nil) then
            return Attack.BurstCount
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "BURSTFIRERATE") then
        if(Attack.BurstFireRate ~= nil) then
            return Attack.BurstFireRate
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "CHARGETIME") then
        if(Attack.ChargeTime ~= nil) then
            if(asString) then
                return Shared.round(Attack.ChargeTime, 2, 1).." s"
            else
                return Attack.ChargeTime
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "CRITCHANCE") then
        if(Attack.CritChance ~= nil) then
            if(asString) then
                return asPercent(Attack.CritChance)
            else
                return Attack.CritChance
            end
        elseif giveDefault then
            if(asString) then
                return asPercent(0)
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "CRITMULTIPLIER") then
        if(Attack.CritMultiplier ~= nil) then
            if(asString) then
                return asMultiplier(Attack.CritMultiplier)
            else
                return Attack.CritMultiplier
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "DAMAGEBIAS") then
        if(hasMultipleTypes(Attack) and Shared.tableCount(Attack.Damage) <= 3) then
            if(asString) then
                --return "[[File:Balance.png|x18px]] "..GetDamageBiasString(Attack, nil, "")
                return GetDamageBiasString(Attack)
            else
                return GetDamageBiasString(Attack)
            end
        else
            if(asString) then
                return ""
            else
                return nil
            end
        end
    elseif(ValName == "DURATION") then
        if(Attack.Duration ~= nil) then
            if(asString) then
                return Shared.round(Attack.Duration, 1, 0).." s"
            else
                return Attack.Duration
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "ELEMENTTYPE") then
        if(Attack.Damage ~= nil) then
            for dType, dmg in Shared.skpairs(Attack.Damage) do
                if(not Shared.contains(Physical, dType) or dmg <= 0) then
                    if(asString) then
                        return Icon._Proc(dType)
                    else
                        return dType
                    end
                end
            end
        elseif asString then
            return ""
        else
            return nil
        end
    elseif(ValName =="ELEMENTTYPENAME") then
        if(Attack.Damage ~= nil) then
            for dType, dmg in Shared.skpairs(Attack.Damage) do
                if(not Shared.contains(Physical, dType) or dmg <= 0) then
                    return dType
                end
            end
        elseif asString then
            return ""
        else
            return nil
        end
    elseif(ValName == "FALLOFF") then
        if(Attack.Falloff ~= nil) then
            local falloffText = "Full damage up to "..Shared.round(Attack.Falloff.StartRange, 2, 1).." m"
            falloffText = falloffText.."<br/>Min damage at "..Shared.round(Attack.Falloff.EndRange, 2, 1).." m"
            if(Attack.Falloff.Reduction ~= nil) then
                falloffText = falloffText.."<br/>"..asPercent(Attack.Falloff.Reduction).." max reduction"
            end
            return falloffText
        else
            return nil
        end
    elseif(ValName == "FIRERATE") then
        local returnVal = 0
        if(Attack.FireRate ~= nil) then
            returnVal = Attack.FireRate
        elseif giveDefault then
            returnVal = 0
        else
            return nil
        end
        if(asString) then
            if(Weapon.Type ~= nil and Weapon.Type ~= "Melee") then
                return Shared.round(returnVal, {3, 1})..p.doPlural(" round<s>/sec", returnVal)
            else
                return Shared.round(returnVal, {3, 1})
            end
        else
            return returnVal
        end
    elseif(ValName == "PELLETCOUNT") then
        if(Attack.PelletCount ~= nil) then
            return Attack.PelletCount
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "PROJECTILESPEED") then
        if(Attack.Bullet ~= nil and Attack.Bullet.Speed ~= nil) then
            if(asString) then
                return Attack.Bullet.Speed.." m/s"
            else
                return Attack.Bullet.Speed
            end
        elseif(giveDefault) then
            if(asString) then
                return "0 m/s"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "PUNCHTHROUGH") then
        if(Attack.PunchThrough ~= nil) then
            if(asString) then
                return Shared.round(Attack.PunchThrough, 2, 1).." m"
            else
                return Attack.PunchThrough
            end
        elseif giveDefault then
            if(asString) then
                return "0 m"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "RADIUS") then
        if(Attack.Radius ~= nil) then
            if(asString) then
                return Shared.round(Attack.Radius, 2, 1).." m"
            else
                return Attack.Radius
            end
        elseif giveDefault then
            if(asString) then
                return "0 m"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "RANGE") then
        if(Attack.Bullet ~= nil and Attack.Bullet.Range ~= nil) then
            if(asString) then
                return Attack.Bullet.Range.." m"
            else
                return Attack.Bullet.Range
            end
        elseif(giveDefault) then
            if(asString) then
                return "0 m"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "STANCES") then
        return getWeaponStanceList(Weapon)    
    elseif(ValName == "STATUSCHANCE") then
        if(Attack.StatusChance ~= nil) then
            if(asString) then
                return asPercent(Attack.StatusChance)
            else
                return Attack.StatusChance
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "TRIGGER") then
        if(Attack.Trigger ~= nil) then
            return Attack.Trigger
        elseif giveDefault then
            return 0
        else
            return nil
        end
    else
        return "ERROR: No such value "..ValName
    end
end
 
local function getValue(Weapon, ValName, giveDefault, asString)
    if(giveDefault == nil) then giveDefault = false end
    if(asString == nil) then asString = false end
 
    if(type(ValName) == "table") then
        local VName1 = string.upper(ValName[1])
        local VName2 = string.upper(ValName[2])
        if(VName1 == nil or VName2 == nil) then
            return nil
        end
 
        if(VName1 == "ATTACK" or VName1 == "NORMALATTACK" or VName1 == "NORMAL") then
            return getAttackValue(Weapon, Weapon, VName2, giveDefault, asString)
        elseif(VName1 == "AREA" or VName1 == "AREAATTACK") then
            return getAttackValue(Weapon, Weapon.AreaAttack, VName2, giveDefault, asString)
        elseif(VName1 == "SECONDARYAREA" or VName1 == "SECONDARYAREAATTACK") then
            return getAttackValue(Weapon, Weapon.SecondaryAreaAttack, VName2, giveDefault, asString)
        elseif(VName1 == "CHARGE" or VName1 == "CHARGEATTACK") then
            return getAttackValue(Weapon, Weapon.ChargeAttack, VName2, giveDefault, asString)
        elseif(VName1 == "CHARGEDTHROW" or VName1 == "CHARGEDTHROWATTACK") then
            return getAttackValue(Weapon, Weapon.ChargedThrowAttack, VName2, giveDefault, asString)
        elseif(VName1 == "THROW" or VName1 == "THROWATTACK") then
            return getAttackValue(Weapon, Weapon.ThrowAttack, VName2, giveDefault, asString)
        elseif(VName1 == "SECONDARY" or VName1 == "SECONDARYATTACK") then
            return getAttackValue(Weapon, Weapon.SecondaryAttack, VName2, giveDefault, asString)
        else
            return "ERROR: No such attack '"..VName1.."'"
        end
    end
 
    ValName = string.upper(ValName)
    if(ValName == "NAME") then
        if(Weapon.Name ~= nil) then
            return Weapon.Name
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "ACCURACY") then
        if(Weapon.Accuracy ~= nil) then
            return Weapon.Accuracy
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "AMMOTYPE") then
        if(Weapon.AmmoType ~= nil) then
            return Weapon.AmmoType
        elseif giveDefault then
            if(Weapon.Type ~= nil) then
                if(Weapon.Type == "Secondary") then
                    return "Pistol"
                elseif(Weapon.Type == "Primary") then
                    if(Weapon.Class == nil or Weapon.Class == "Rifle") then
                        return "Rifle"
                    elseif(Weapon.Class == "Shotgun") then
                        return "Shotgun"
                    elseif(Weapon.Class == "Bow") then
                        return "Bow"
                    elseif(Weapon.Class == "Sniper" or Weapon.Class == "Launcher") then
                        return "Sniper"
                    end
                end
            end
        else
            return nil
        end
    elseif(ValName == "AUGMENT") then
        local augments = getAugments(Weapon)
        if(Shared.tableCount(augments) > 0) then
            local AugString = ""
            for i, Aug in pairs(augments) do
                if(i>1) then AugString = AugString.."<br/>" end
                AugString = AugString.."[["..Aug.Name.."]]"
            end
            return AugString
        else
            return nil
        end
    elseif(ValName == "CHANNELMULT") then
        if(Weapon.ChannelMult ~= nil) then
            if(asString) then
                return asMultiplier(Weapon.ChannelMult)
            else
                return Weapon.ChannelMult
            end
        elseif giveDefault then
            if(asString) then
                return "1.5x"
            else
                return 1.5
            end
        else
            return nil
        end
    elseif(ValName == "CLASS") then
        if(Weapon.Class ~= nil) then
            if(asString and Weapon.Type == "Melee") then
                return "[[:Category:"..Weapon.Class.."|"..Weapon.Class.."]]"
            else
                return Weapon.Class
            end
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "CONCLAVE") then
        if(Weapon.Conclave ~= nil) then
            if(asString) then
                if(Weapon.Conclave) then return "Yes" else return "No" end
            else
                return Weapon.Conclave
            end
        elseif giveDefault then
            return false
        else
            return nil
        end
    elseif(ValName == "DISPOSITION") then
        if(Weapon.Disposition ~= nil) then
            if(asString) then
                return Icon._Dis(Weapon.Disposition)
            else
                return Weapon.Disposition
            end
        elseif giveDefault then
            if(asString) then
                return "Unknown"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "FAMILY") then
        if(Weapon.Family ~= nil) then
            return Weapon.Family
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "FINISHERDAMAGE") then
        if(Weapon.FinisherDamage ~= nil) then
            if(asString) then
                return Shared.round(Weapon.FinisherDamage, 2, 1)
            else
                return Weapon.FinisherDamage
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "IMAGE") then
        if(Weapon.Image ~= nil) then
            return Weapon.Image
        elseif giveDefault then
            return "Panel.png"
        else
            return nil
        end
    elseif(ValName == "INTRODUCED") then
        if(Weapon.Introduced ~= nil) then
            return Weapon.Introduced
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "JUMPATTACK") then
        if(Weapon.JumpAttack ~= nil) then
            if(asString) then
                if(Weapon.JumpElement ~= nil) then
                    return Icon._Proc(Weapon.JumpElement).." "..Shared.round(Weapon.JumpAttack, 2, 1)
                else
                    return Shared.round(Weapon.JumpAttack, 2, 1)
                end
            else
                return Weapon.JumpAttack
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "JUMPELEMENT") then
        if(Weapon.JumpElement ~= nil) then
            return Weapon.JumpElement
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "JUMPRADIUS") then
        if(Weapon.JumpRadius ~= nil) then
            if(asString) then
                return Shared.round(Weapon.JumpRadius, 2, 1).." m"
            else
                return Weapon.JumpRadius
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "MAGAZINE") then
        if(Weapon.Magazine ~= nil) then
            if(asString) then
            return Weapon.Magazine..p.doPlural(" round<s>/mag", Weapon.Magazine)
            else
                return Weapon.Magazine
            end
        elseif giveDefault then
            if(asString) then
                return "0 rounds/mag"
            else
                return 0
            end
        else
            return nil
        end
    elseif(ValName == "MASTERY") then
        if(Weapon.Mastery ~= nil) then
            return Weapon.Mastery
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "MAXAMMO") then
        local returnVal = 0
        if(Weapon.MaxAmmo ~= nil) then
            returnVal = Weapon.MaxAmmo
        elseif giveDefault then
            if(Weapon.Type ~= nil) then
                if(Weapon.Type == "Secondary") then
                    returnVal = 210
                elseif(Weapon.Type == "Primary") then
                    if(Weapon.Class == nil or Weapon.Class == "Rifle") then
                        returnVal = 540
                    elseif(Weapon.Class == "Shotgun") then
                        returnVal = 120
                    elseif(Weapon.Class == "Bow" or Weapon.Class == "Sniper") then
                        returnVal = 72
                    end
                end
            end
        else
            return nil
        end
        if(asString) then
            if(returnVal > 0) then
                return returnVal.." rounds"
            else
                return nil
            end
        else
            if(returnVal > 0) then
                return returnVal
            else
                return nil
            end
        end
    elseif(ValName == "NOISELEVEL") then
        if(Weapon.NoiseLevel ~= nil) then
            return Weapon.NoiseLevel
        elseif giveDefault then
            if(Weapon.Type ~= nil and Weapon.Type ~= "Melee") then
                if(Weapon.Class ~= nil and (Weapon.Class == "Bow" or Weapon.Class == "Thrown")) then
                    return "Silent"
                else
                    return "Alarming"
                end
            else
                return nil
            end
        else
            return nil
        end
    elseif(ValName == "POLARITIES") then
        if(Weapon.Polarities ~= nil) then
            if(asString) then
                return GetPolarityString(Weapon)
            else
                return Weapon.Polarities
            end
        elseif giveDefault then
            if(asString) then
                return "None"
            else
                return {}
            end
        else
            return nil
        end
    elseif(ValName == "RELOAD") then
        if(Weapon.Reload ~= nil) then
            if(asString) then
                return Shared.round(Weapon.Reload, 2, 1).." s"
            else
                return Weapon.Reload
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "SLIDEATTACK") then
        if(Weapon.SlideAttack ~= nil) then
            if(asString) then
                if(Weapon.SlideElement ~= nil) then
                    return Icon._Proc(Weapon.SlideElement).." "..Shared.round(Weapon.SlideAttack, 2, 1)
                else
                    return Shared.round(Weapon.SlideAttack, 2, 1)
                end
            else
                return Weapon.SlideAttack
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "SLIDEELEMENT") then
        if(Weapon.SlideElement ~= nil) then
            return Weapon.SlideElement
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "SNIPERCOMBORESET") then
        if(Weapon.SniperComboReset ~= nil) then
            if(asString) then
                return Shared.round(Weapon.SniperComboReset, 2, 1).." s"
            else
                return Weapon.SniperComboReset
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "SNIPERCOMBOMIN") then
        if(Weapon.SniperComboMin ~= nil) then
            if(asString) then
                return Weapon.SniperComboMin.." shots"
            else
                return Weapon.SniperComboMin
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "STAGGER") then
        if(Weapon.Stagger ~= nil) then
            return Weapon.Stagger
        elseif giveDefault then
            return "No"
        else
            return nil
        end
    elseif(ValName == "STANCEPOLARITY") then
        if(Weapon.StancePolarity ~= nil) then
            if(asString) then
                return Icon._Pol(Weapon.StancePolarity)
            else
                return Weapon.StancePolarity
            end
        elseif giveDefault then
            return "None"
        else
            return nil
        end
    elseif(ValName == "SYNDICATEEFFECT") then
        if(Weapon.SyndicateEffect ~= nil) then
            if(asString) then
                return "[["..Weapon.SyndicateEffect.."]]"
            else
                return Weapon.SyndicateEffect
            end
        else
            return nil
        end
    elseif(ValName == "TRAITS") then
        if(Weapon.Traits ~= nil) then
            return Weapon.Traits
        elseif giveDefault then
            return {}
        else
            return nil
        end
    elseif(ValName == "TYPE") then
        if(Weapon.Type ~= nil) then
            return Weapon.Type
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "USERS") then
        if(Weapon.Users ~= nil) then
            if(asString) then
                local result = ""
                for i, str in pairs(Weapon.Users) do
                    if(i > 1) then result = result..'<br/>' end
                    result = result..str
                end
                return result
            else
                return Weapon.Users
            end
        elseif giveDefault then
            return {}
        else
            return nil
        end
    elseif(ValName == "WALLATTACK") then
        if(Weapon.WallAttack ~= nil) then
            if(asString) then
                if(Weapon.WallElement ~= nil) then
                    return Icon._Proc(Weapon.WallElement).." "..Shared.round(Weapon.WallAttack, 2, 1)
                else
                    return Shared.round(Weapon.WallAttack, 2, 1)
                end
            else
                return Weapon.WallAttack
            end
        elseif giveDefault then
            return 0
        else
            return nil
        end
    elseif(ValName == "WALLELEMENT") then
        if(Weapon.WallElement ~= nil) then
            return Weapon.WallElement
        elseif giveDefault then
            return ""
        else
            return nil
        end
    elseif(ValName == "ZOOM") then
        if(Weapon.Zoom ~= nil) then
            if(asString) then
                local result = ""
                for i, str in pairs(Weapon.Zoom) do
                    if(i > 1) then result = result..'<br/>' end
                    result = result..str
                end
                return result
            else
                return Weapon.Zoom
            end
        else
            return nil
        end
    else
        return getAttackValue(Weapon, Weapon, ValName, giveDefault, asString)
    end
end
 
function p.getValue(frame)
    local WeapName = frame.args[1]
    local ValName1 = frame.args[2]
    local ValName2 = frame.args[3]
    if(WeapName == nil) then
        return "ERROR: No weapon name included"
    elseif(ValName1 == nil) then
        return "ERROR: No value selected"
    end
 
    local theWeap = p.getWeapon(WeapName)
    if(theWeap == nil) then
        return "ERROR: "..WeapName.." not found in Module:Weapons/data"
    end
 
    local vName
    local useDefault
    if(ValName2 == nil or ValName2 == "") then
        vName = ValName1
        useDefault = Shared.contains(UseDefaultList, string.upper(ValName1))
    else
        vName = {ValName1, ValName2}
        useDefault = Shared.contains(UseDefaultList, string.upper(ValName2))
    end
 
 
    return getValue(theWeap, vName, useDefault, true)
end
 
local function BuildGunComparisonRow(Weapon)
    local styleString = "border: 1px solid lightgray;"
    local td = '|| style = "'..styleString..'" |'
    local result = ''
    if(hasAttack(Weapon, 'Normal')) then
        result = '\n|-\n| style = "'..styleString..'"|[['..Weapon.Name.."]]"
        result = result..td..GetDamageString(Weapon)
        result = result..td..asPercent(Weapon.CritChance)..td..asMultiplier(Weapon.CritMultiplier)
        result = result..td..asPercent(Weapon.StatusChance)..td..Shared.round(Weapon.FireRate, 3, 2)..td..Weapon.Magazine..td..Weapon.Reload.." s"..td..Weapon.Trigger
        result = result..td..Weapon.Mastery
        if(Weapon.Disposition ~= nil) then
            result = result..'||data-sort-value="'..Weapon.Disposition..'" style="'..styleString..'"|'..Icon._Dis(Weapon.Disposition)
        else
            result = result..'||data-sort-value="0" style="'..styleString..'"|Unknown'
        end
    end
 
    return result
end
 
local function BuildMeleeComparisonRow(Weapon,addClass)
    local styleString = "border: 1px solid lightgray;"
    local td = '|| style = "'..styleString..'" |'
    if(addClass == nil) then addClass = false end
    local result = '\n|-\n| style = "'..styleString..'"|[['..Weapon.Name.."]]"
    if(addClass) then
        result = result..td..Weapon.Class
    end
    result = result..td..GetDamageString(Weapon)
    result = result..td..Weapon.SlideAttack
    result = result..td..Shared.round(Weapon.FireRate, 3, 2)..td..asPercent(Weapon.CritChance)..td..asMultiplier(Weapon.CritMultiplier)
    result = result..td..asPercent(Weapon.StatusChance)
    result = result..td..Weapon.Mastery..td..GetStancePolarity(Weapon)
    if(Weapon.Disposition ~= nil) then
        result = result..'||data-sort-value="'..Weapon.Disposition..'" style="'..styleString..'"|'..Icon._Dis(Weapon.Disposition)
    else
        result = result..'||data-sort-value="0" style="'..styleString..'"|Unknown'
    end
    return result
end
 
local function BuildGunComparisonTable(Weapons)
    local styleString = "background-color:transparent;color:black;border: 1px solid black;border-collapse: collapse;"
    local tHeader = ""
    tHeader = tHeader..'\n{| cellpadding="1" cellspacing="0" class="sortable" style="margin:auto;text-align:center;border:1px solid black;font-size:11px;"'
    tHeader = tHeader..'\n!style="'..styleString..'"|Name'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Damage 2.0|Damage]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Critical_Hit|Critical Chance]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Critical_Hit|Critical Damage]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Status_Effect|Status Chance]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Fire Rate]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Ammo|Magazine Size]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Reload_Speed|Reload Time]]'
    tHeader = tHeader..'\n! style="'..styleString..'"|[[Fire_Rate|Trigger Type]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Mastery_Rank|Mastery Rank]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Riven Mods#Disposition|Disposition]]'
    local tRows = ""
    for i, Weap in pairs(Weapons) do
        local didWork, rowStr = pcall(BuildGunComparisonRow, Weap)
        if(didWork)then
            tRows = tRows..rowStr
        else
            mw.log("Error trying to build row for "..Weap.Name..": "..rowStr)
        end
    end
 
    return tHeader..tRows.."\n|}[[Category:Automatic Comparison Table]]"
end
 
local function BuildMeleeComparisonTable(Weapons, addClass)
    if(addClass == nil) then addClass = false end
    local styleString = "background-color:transparent;color:black;border: 1px solid black;border-collapse: collapse;"
    local tHeader = ""
    tHeader = tHeader..'\n{| cellpadding="1" cellspacing="0" class="sortable" style="margin:auto;text-align:center;font-size:11px;"'
    tHeader = tHeader..'\n! style="'..styleString..'"|Name'
    if(addClass) then
        tHeader = tHeader..'\n! style="'..styleString..'"|Type'
    end
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Damage 2.0|Damage]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Damage 2.0|Slide]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Maneuvers#Melee|Attack Speed]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Critical Hit|Critical Chance]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Critical Hit|Critical Damage]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Status Chance]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Mastery_Rank|Mastery Rank]]'
    tHeader = tHeader..'\n! style="'..styleString..'"|[[Stance]]'
    tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|[[Riven Mods#Disposition|Disposition]]'
 
    local tRows = ""
    for i, Weap in pairs(Weapons) do
        tRows = tRows..BuildMeleeComparisonRow(Weap, addClass)
    end
 
    return tHeader..tRows.."\n|}[[Category:Automatic Comparison Table]]"
end
 
local function buildInfoboxRow(Label, Text, Collapse, Digits, Addon)
    local result = ""
 
    if(Collapse == nil) then
        Collapse = false
    elseif(Collapse == 1) then
        Collapse = true
    end
    if(Text ~= nil) then
        result = '<div style="margin-left:-3px;" '
        if(Collapse) then
            result = result..'class="Infobox_Collapsible"'
        end
        result = result..'>'
        result = result..'\n{| style="width:100%;"'
        result = result..'\n|-'
        result = result..'\n| class="left" | <span style="white-space:nowrap;">'
            result = result.."'''"..Label.."'''"
        result = result..'</span>'
        result = result..'\n| class="right" | '
        if(Digits == nil) then
            result = result..Text
        else
            result = result..Shared.round(Text, Digits)
        end
        if(Addon ~= nil) then
            result = result..p.doPlural(Addon, Text)
        end
        result = result..'\n|}'
        result = result..'\n</div>'
    end
    return result
end
 
local function buildInfoboxCategory(CategoryName)
    local result = '\n|-\n! colspan="2" class="category" | '..CategoryName
    result = result..'\n|-\n| colspan="2" |'
    return result
end
 
local function makeAttackInfoboxRows(Weapon, Attack, AttackName)
    if(Attack == nil or Attack.Damage == nil) then
        return ""
    end
    local result = buildInfoboxCategory(AttackName)
 
    local Physical = GetDamage(Attack, "Physical")
    if(Physical > 0) then
        result = result..buildInfoboxRow("[[Damage 2.0|Physical Damage]]", getAttackValue(Weapon, Attack, "Physical", true, true))
        result = result..buildInfoboxRow(Icon._Proc("Impact", "Text", "white", nil, true), getAttackValue(Weapon, Attack, "Impact", true, true), true)
        result = result..buildInfoboxRow(Icon._Proc("Puncture", "Text", "white", nil, true), getAttackValue(Weapon, Attack, "Puncture", true, true), true)
        result = result..buildInfoboxRow(Icon._Proc("Slash", "Text", "white", nil, true), getAttackValue(Weapon, Attack, "Slash", true, true), true)
    end
 
    for element, damage in Shared.skpairs(Attack.Damage) do
        if(element ~= "Impact" and element ~= "Puncture" and element ~= "Slash") then
            result = result..buildInfoboxRow(Icon._Proc(element, "Text", "white", nil, true), getAttackValue(Weapon, Attack, element, true, true))
        end
    end
    result = result..buildInfoboxRow("Best Damage %", GetDamageBiasString(Attack), true)
    result = result..buildInfoboxRow("[[Fire Rate#Charged Weapons|Charge Time]]", Attack.ChargeTime, nil, 1, " s")
    result = result..buildInfoboxRow("[[Critical Hit#Critical Hit Chance|Crit Chance]]", getAttackValue(Weapon, Attack, "CritChance", false, true))
    result = result..buildInfoboxRow("[[Critical Hit#Critical Damage Multiplier|Crit Multiplier]]", getAttackValue(Weapon, Attack, "CritMultiplier", false, true))
    result = result..buildInfoboxRow("[[Status Chance]]", getAttackValue(Weapon, Attack, "StatusChance", false, true))
    result = result..buildInfoboxRow("[[Punch Through]]", getAttackValue(Weapon, Attack, "PunchThrough", false, true))
    result = result..buildInfoboxRow("[[Fire Rate]]", getAttackValue(Weapon, Attack, "FireRate", false, true), nil)
    result = result..buildInfoboxRow("Fire Rate per Burst", Attack.BurstFireRate, true, {2, 1}, " round<s>/sec/burst")
    result = result..buildInfoboxRow("[[Multishot|Pellet Count]]", Attack.PelletCount, nil, 0, " pellet<s>/round")
    if(Attack.Bullet ~= nil) then
        if(Attack.Bullet.Speed ~= nil) then
            result = result..buildInfoboxRow("[[Projectile Speed|Flight Speed]]", Attack.Bullet.Speed, true, 2, " m/s")
        else
            result = result..buildInfoboxRow("[[Projectile Speed|Flight Speed]]", Attack.Bullet.Type, true)
        end
    end
    result = result..buildInfoboxRow("Radius", getAttackValue(Weapon, Attack, "Radius", false, true), nil)
    result = result..buildInfoboxRow("Duration", getAttackValue(Weapon, Attack, "Duration", false, true), nil)
    if(AttackName ~= "Normal Attacks") then
        result = result..buildInfoboxRow("Trigger", getAttackValue(Weapon, Attack, "Trigger", false, true), nil)
    end
    if(Attack.Falloff ~= nil) then
        local falloffText = "Full damage up to "..Shared.round(Attack.Falloff.StartRange, 2, 1).." m"
        falloffText = falloffText.."<br/>Min damage at "..Shared.round(Attack.Falloff.EndRange, 2, 1).." m"
        if(Attack.Falloff.Reduction ~= nil) then
            falloffText = falloffText.."<br/>"..asPercent(Attack.Falloff.Reduction).." max reduction"
        end
        result = result..buildInfoboxRow("Damage Falloff", falloffText)
    end
 
    return result
end
 
--Returns a list of weapons for a stance
--Adds a ✓ if the weapon matches the polarity
function p.getStanceWeaponList(frame)
    local StanceName = frame.args ~= nil and frame.args[1] or frame
    local Stance = p.getStance(StanceName)
 
    if(Stance == nil) then
        return "ERROR: "..StanceName.." not found"
    end
 
    local weaps = getMeleeWeapons(Stance.Class, Stance.PvP)
    local result = ""
 
    for i, weap in Shared.skpairs(weaps) do
        if (string.len(result) > 0) then
            result = result.."\n"
        end
 
        result = result.."*[["..weap.Name.."]]"
 
        if(weap.StancePolarity == Stance.Polarity) then
            result = result.." ✓"
        end
    end
 
    return result
end
 
--Returns a list of stances for a weapon
--Adds the polarity for each stance
function p.getWeaponStanceList(frame)
    local WeaponName = frame.args ~= nil and frame.args[1] or frame
    local Weapon = getWeapon(WeaponName)
 
    if(Weapon == nil) then
        return "ERROR: "..WeaponName.." not found"
    end
 
    return getWeaponStanceList(Weapon)
end
 
function p.getStanceGallery(frame)
    local StanceType = frame.args ~= nil and frame.args[1] or frame
    local Stances = getStances(StanceType, true)
    local result = "=="..StanceType.." [[Stance|Stance Mods]]=="
    result = result..'\n{| style="margin:auto;text-align:center;"'
    local nameRow = ''
    for i, Stance in pairs(Stances) do
        local theImage = Stance.Image ~= nil and Stance.Image or "Panel.png"
        if((i - 1) % 4 == 0) then 
            result = result..nameRow..'\n|-' 
            nameRow = '\n|-'
        end
        result = result..'\n| style="width:165px" |[[File:'..Stance.Image..'|150px|link='..Stance.Name..']]'
        nameRow = nameRow..'\n| style="vertical-align: text-top;" |[['..Stance.Name..']]'
        if(Stance.PvP ~= nil and Stance.PvP) then
            nameRow = nameRow..'<br/>([[Conclave]] only)'
        end
    end
    result = result..nameRow
    result = result..'\n|}'
    return result
end
 
local function getWeaponGallery(Weapons)
    local result = '{| style="margin:auto;text-align:center;"'
    local nameRow = ''
    for i, Weapon in pairs(Weapons) do
        local theImage = Weapon.Image ~= nil and Weapon.Image or "Panel.png"
        if((i - 1) % 4 == 0) then 
            result = result..nameRow..'\n|-' 
            nameRow = '\n|-'
        end
        result = result..'\n| style="width:165px" |[[File:'..theImage..'|150px|link='..Weapon.Name..']]'
        nameRow = nameRow..'\n| style="vertical-align: text-top;" |[['..Weapon.Name..']]'
    end
    result = result..nameRow
    result = result..'\n|}'
    return result
end
 
function p.getMeleeWeaponGallery(frame)
    local Type = frame.args ~= nil and frame.args[1] or frame
    if(Type == nil) then
        return ""
    end
    local WeapArray = getMeleeWeapons(Type)
    local result = "=="..Type.." Weapons==\n"
    result = result..getWeaponGallery(WeapArray)
    return result
end
 
function p.getMeleeComparisonTable(frame)
    local Type = frame.args ~= nil and frame.args[1] or nil
    local WeapArray = getMeleeWeapons(Type)
    local addClass = Type == nil or Shared.contains(Type, ",")
    return BuildMeleeComparisonTable(WeapArray, addClass)
end
 
function p.getSecondaryComparisonTable()
    local WeapArray = getWeapons(function(x) return x.Type == "Secondary" end)
    return BuildGunComparisonTable(WeapArray)
end
 
function p.getPrimaryComparisonTable()
    local WeapArray = getWeapons(function(x) return x.Type == "Primary" end)
    return BuildGunComparisonTable(WeapArray)
end
 
function p.getPolarityTable()
    local tHeader = ""
    tHeader = tHeader..'\n{| style="width: 100%; border-collapse: collapse; cellpadding: 2" border="1"'
    tHeader = tHeader..'\n! colspan="2" |Primary Weapons'
    tHeader = tHeader..'\n! colspan="2" |Secondary Weapons'
    tHeader = tHeader..'\n! colspan="2" |Melee Weapons'
    local tRows = ""
 
    local Melees = getWeapons(function(x) return p.isMelee(x) and x.Polarities ~= nil and Shared.tableCount(x.Polarities) > 0 end)
    local Pistols = getWeapons(function(x) return x.Type == "Secondary" and  x.Polarities ~= nil and Shared.tableCount(x.Polarities) > 0 end)
    local Primaries = getWeapons(function(x) return (x.Type == "Primary") and  x.Polarities ~= nil and Shared.tableCount(x.Polarities) > 0 end)
 
    local ACount = Shared.tableCount(Melees)
    local maxLen = ACount
    local BCount = Shared.tableCount(Pistols)
    if(BCount > maxLen) then
        maxLen = BCount
    end
    local CCount = Shared.tableCount(Primaries)
    if(CCount > maxLen) then
        maxLen = CCount
    end
 
    for i=1, maxLen, 1 do
        tRows = tRows.."\n|-"
        if(i <= CCount) then
            tRows = tRows.."\n|[["..Primaries[i].Name.."]]||"..GetPolarityString(Primaries[i])
        else
            tRows = tRows.."\n| ||"
        end
        if(i <= BCount) then
            tRows = tRows.."\n|[["..Pistols[i].Name.."]]||"..GetPolarityString(Pistols[i])
        else
            tRows = tRows.."\n| ||"
        end
        if(i <= ACount) then
            tRows = tRows.."\n|[["..Melees[i].Name.."]]||"..GetPolarityString(Melees[i])
        else
            tRows = tRows.."\n| ||"
        end
    end
 
    return tHeader..tRows.."\n|}"
end
 
function buildCompareString(Val1, Val2, ValName, Digits, Addon, Words, Start)
    if(Val1 == nil or Val2 == nil) then
        return ""
    end
    local V1Str = Val1
    local V2Str = Val2
    if(Digits ~= nil) then
        V1Str = Shared.round(Val1, Digits)
        V2Str = Shared.round(Val2, Digits)
    end
    if(Addon ~= nil) then
        V1Str = V1Str..p.doPlural(Addon, Val1)
        V2Str = V2Str..p.doPlural(Addon, Val2)
    end
    local bigWord = Words ~= nil and Words[1] or "Higher"
    local smallWord = Words ~= nil and Words[2] or "Lower"
    local start = Start ~= nil and Start or "\n**"
 
    if(Val1 > Val2) then
        return start.." "..bigWord.." "..ValName.." ("..V1Str.." vs. "..V2Str..")"
    elseif(Val2 > Val1) then
        return start.." "..smallWord.." "..ValName.." ("..V1Str.." vs. "..V2Str..")"
    else
        return ""
    end
end
 
function buildGunComparisonString(Weapon1, Weapon2)
    local result = "* "..Weapon1.Name..", compared to [["..Weapon2.Name.."]]:"
 
    if(hasAttack(Weapon1, "Normal") == "yes" and hasAttack(Weapon2, "Normal") == "yes") then
        local dmgString = ""
        dmgString = dmgString..buildCompareString(GetDamage(Weapon1), GetDamage(Weapon2), "base damage", {2, 1})
        dmgString = dmgString..buildCompareString(Weapon1.Damage["Impact"], Weapon2.Damage["Impact"], Icon._Proc("Impact", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
        dmgString = dmgString..buildCompareString(Weapon1.Damage["Puncture"], Weapon2.Damage["Puncture"], Icon._Proc("Puncture", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
        dmgString = dmgString..buildCompareString(Weapon1.Damage["Slash"], Weapon2.Damage["Slash"], Icon._Proc("Slash", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
        if(string.len(dmgString) > 0 and GetDamage(Weapon1) == GetDamage(Weapon2)) then
            dmgString = "\n**Equal base damage, but different composition:"..dmgString    
        end
        result = result..dmgString
    end
    if(hasAttack(Weapon1, "Charge") == "yes" and hasAttack(Weapon2, "Charge") == "yes") then
        result = result..buildCompareString(GetDamage(Weapon1.ChargeAttack), GetDamage(Weapon2.ChargeAttack), "charge attack damage", {2, 1})
    end
    if(hasAttack(Weapon1, "Area") == "yes" and hasAttack(Weapon2, "Area") == "yes") then
        result = result..buildCompareString(GetDamage(Weapon1.AreaAttack), GetDamage(Weapon2.AreaAttack), "area attack damage", {2, 1})
    end
    if(hasAttack(Weapon1, "Secondary") == "yes" and hasAttack(Weapon2, "Secondary") == "yes") then
        result = result..buildCompareString(GetDamage(Weapon1.SecondaryAttack), GetDamage(Weapon2.SecondaryAttack), "secondary attack damage", {2, 1})
    end
 
    if(hasAttack(Weapon1, "Normal") == "yes" and hasAttack(Weapon2, "Normal") == "yes") then
        result = result..buildCompareString((Weapon1.CritChance * 100), (Weapon2.CritChance * 100), "critical chance", 2, "%")
        result = result..buildCompareString(Weapon1.CritMultiplier, Weapon2.CritMultiplier, "critical damage multiplier", 2, "x")
        result = result..buildCompareString((Weapon1.StatusChance * 100), (Weapon2.StatusChance * 100), "status chance", 2, "%")
        result = result..buildCompareString(Weapon1.FireRate, Weapon2.FireRate, "fire rate", 2, " round<s>/sec")
    end
    result = result..buildCompareString(Weapon1.Magazine, Weapon2.Magazine, "magazine", 0, " round<s>", {"Larger", "Smaller"})
    result = result..buildCompareString(Weapon1.MaxAmmo, Weapon2.MaxAmmo, "max ammo capacity", 0, " round<s>", {"Larger", "Smaller"})
    result = result..buildCompareString(Weapon1.Reload, Weapon2.Reload, "reload speed", 2, " s", {"Slower", "Faster"})
    result = result..buildCompareString(Weapon1.Spool, Weapon2.Spool, "spool-up", 0, " round<s>", {"Slower", "Faster"})
 
    --Handling Syndicate radial effects
    if(Weapon1.SyndicateEffect ~= nil and Weapon2.SyndicateEffect == nil) then
        result = result.."\n** Innate [["..Weapon1.SyndicateEffect.."]] effect"
    elseif(Weapon2.SyndicateEffect ~= nil and Weapon1.SyndicateEffect == nil) then
        result = result.."\n** Lack of an innate [["..Weapon2.SyndicateEffect.."]] effect"
    elseif(Weapon1.SyndicateEffect ~= nil and Weapon2.SyndicateEffect ~= nil and Weapon1.SyndicateEffect ~= Weapon2.SyndicateEffect2) then
        result = result.."\n** Different innate [[Syndicate Radial Effects|Syndicate Effect]]: [["..Weapon1.SyndicateEffect.."]] vs. [["..Weapon2.SyndicateEffect.."]]"
    end
 
    --Handling Polarities
    local Pol1 = Weapon1.Polarities ~= nil and Weapon1.Polarities or {}
    local Pol2 = Weapon2.Polarities ~= nil and Weapon2.Polarities or {}
    local count1 = Shared.tableCount(Pol1)
    local count2 = Shared.tableCount(Pol2)
    local isDifferent = count1 ~= count2
    if(not isDifferent and count1 > 0) then
        table.sort(Pol1, function(x, y) return x < y end)
        table.sort(Pol2, function(x, y) return x < y end)
        for i, pol in pairs(Pol1) do
            if(pol ~= Pol2[i]) then
                isDifferent = true
            end
        end
    end
 
    if(isDifferent) then
        result = result.."\n** Different polarities ("..GetPolarityString(Weapon1).." vs. "..GetPolarityString(Weapon2)..")"
    end
 
    result = result..buildCompareString(Weapon1.Mastery, Weapon2.Mastery, "[[Mastery Rank]] required", 0)
    return result
end
 
function buildMeleeComparisonString(Weapon1, Weapon2)
    local result = "* "..Weapon1.Name..", compared to [["..Weapon2.Name.."]]:"
 
    local dmgString = ""
    dmgString = dmgString..buildCompareString(GetDamage(Weapon1), GetDamage(Weapon2), "base damage", {2, 1})
    dmgString = dmgString..buildCompareString(Weapon1.Damage["Impact"], Weapon2.Damage["Impact"], Icon._Proc("Impact", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
    dmgString = dmgString..buildCompareString(Weapon1.Damage["Puncture"], Weapon2.Damage["Puncture"], Icon._Proc("Puncture", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
    dmgString = dmgString..buildCompareString(Weapon1.Damage["Slash"], Weapon2.Damage["Slash"], Icon._Proc("Slash", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
    if(string.len(dmgString) > 0 and GetDamage(Weapon1) == GetDamage(Weapon2)) then
        dmgString = "\nEqual base damage, but different composition:"..dmgString    
    end
    result = result..dmgString
 
    result = result..buildCompareString((Weapon1.CritChance * 100), (Weapon2.CritChance * 100), "critical chance", 2, "%")
    result = result..buildCompareString(Weapon1.CritMultiplier, Weapon2.CritMultiplier, "critical damage multiplier", {2, 1}, "x")
    result = result..buildCompareString((Weapon1.StatusChance * 100), (Weapon2.StatusChance * 100), "status chance", 2, "%")
    result = result..buildCompareString(Weapon1.FireRate, Weapon2.FireRate, "attack speed", 2)
    result = result..buildCompareString(Icon._Pol(Weapon1.StancePolarity), Icon._Pol(Weapon2.StancePolarity), "Stance Polarity", nil, nil, {"Different", "Different"})
    result = result..buildCompareString(Weapon1.ChannelMult, Weapon2.ChannelMult, "Channeling Multiplier", 1, "x", {"Larger", "Smaller"})
    result = result..buildCompareString(Weapon1.Mastery, Weapon2.Mastery, "[[Mastery Rank]] required", 0)
    return result
end
 
function p.buildComparison(frame)
    local WeapName1 = frame.args[1]
    local WeapName2 = frame.args[2]
 
    if(WeapName1 == nil or WeapName2 == nil) then
        return '<span style="color:red">ERROR: Must compare two weapons</span>'
    end
 
    local Weapon1 = p.getWeapon(WeapName1)
    if(Weapon1 == nil) then
        return '<span style="color:red">ERROR: Could not find '..WeapName1..'</span>'
    end
    local Weapon2 = p.getWeapon(WeapName2)
    if(Weapon2 == nil) then
        return '<span style="color:red">ERROR: Could not find '..WeapName2..'</span>'
    end
 
    if(p.isMelee(Weapon1)) then
        return buildMeleeComparisonString(Weapon1, Weapon2).."[[Category:Automatic Comparison]]"
    else
        return buildGunComparisonString(Weapon1, Weapon2).."[[Category:Automatic Comparison]]"
    end
end
 
function p.buildFamilyComparison(frame)
    local WeapName = frame.args ~= nil and frame.args[1] or frame
    if(WeapName == nil) then
        return '<span style="color:red">ERROR: Must provide a Weapon name</span>'
    end
 
    local Weapon = p.getWeapon(WeapName)
    if(Weapon == nil) then
        return '<span style="color:red">ERROR: Could not find '..WeapName1..'</span>'
    end
    if(Weapon.Family == nil) then
        return '<span style="color:red">ERROR: '..WeapName..' doesn\'t have a family</span>'
    end
 
    local relatives = getFamily(Weapon.Family)
    local result = {}
    for i, NewWeapon in pairs(relatives) do
        if(WeapName ~= NewWeapon.Name) then
            if(p.isMelee(NewWeapon)) then
                table.insert(result, buildMeleeComparisonString(Weapon, NewWeapon))
            else
                table.insert(result, buildGunComparisonString(Weapon, NewWeapon))
            end
        end
    end
    return table.concat(result, "\n")
end
 
function p.buildAutoboxCategories(frame)
    local WeapName = frame.args ~= nil and frame.args[1] or frame
    local Weapon = p.getWeapon(WeapName)
    local result = "[[Category:Automatic Weapon Box]][[Category:Weapons]]"
    if(Weapon == nil) then
        return ""
    end
    if(Weapon.Type ~= nil) then
        result= result.."[[Category:"..Weapon.Type.." Weapons]]"
    end
    if(Weapon.Class ~= nil) then
        result= result.."[[Category:"..Weapon.Class.."]]"
    end
 
    local augments = getAugments(Weapon)
    if(Shared.tableCount(augments) > 0) then
        result = result.."[[Category:Augmented Weapons]]"
    end
 
    if(HasTrait(Weapon, "Prime")) then
        result = result.."[[Category:Prime]][[Category:Prime Weapons]]"
        if(HasTrait(Weapon, "Never Vaulted")) then
            result = result.."[[Category:Never Vaulted]]"
        elseif(HasTrait(Weapon, "Vaulted")) then
            result = result.."[[Category:Vaulted]]"
        end
    end
 
    if(Weapon.Damage ~= nil) then
        local bestPercent, bestElement = GetDamageBias(Weapon)
        if(bestElement == "Impact" or bestElement == "Puncture" or bestElement == "Slash") then
            result = result.."[[Category:"..bestElement.." Damage Weapons]]"
        end
 
        for key, value in Shared.skpairs(Weapon.Damage) do
            if(key ~= "Impact" and key ~= "Puncture" and key ~= "Slash") then
                result = result.."[[Category:"..key.." Damage Weapons]]"
            end
        end
    end
 
    return result
end
 
function p.buildAutobox(frame)
    local WeapName = frame.args ~= nil and frame.args[1] or frame
    local Weapon = p.getWeapon(WeapName)
    if(Weapon == nil) then
        return buildInfoboxRow("ERROR", "Weapon not found in [[Module:Weapons/data]]")
    end
 
    if(p.isMelee(Weapon)) then
        return p.buildMeleeAutobox(frame)
    else
        return p.buildGunAutobox(frame)
    end
end
 
function p.buildGunAutobox(frame)
    local WeapName = frame.args ~= nil and frame.args[1] or frame
    local Weapon = p.getWeapon(WeapName)
    if(Weapon == nil) then
        return buildInfoboxRow("ERROR", "Weapon not found in [[Module:Weapons/data]]")
    end
    local result = ""
 
    result = '\n|-\n| colspan="2" class="image" | [[File:'..getValue(Weapon, "Image", true)..'|220px]]<br/>'
    result = result..buildInfoboxCategory("Statistics[[Category:Automatic Weapon Box]]")
    result = result..buildInfoboxRow("[[Mastery Rank]]", getValue(Weapon, "Mastery"))
    result = result..buildInfoboxRow("Weapon Slot", getValue(Weapon, "Type"))
    result = result..buildInfoboxRow("Weapon Type", getValue(Weapon, "Class"))
    result = result..buildInfoboxRow("Trigger Type", Weapon.Trigger)
 
 
 
    result = result..buildInfoboxCategory("Utility")
    result = result..buildInfoboxRow("[[Ammo#Ammo Packs|Ammo Type]]", Weapon.AmmoType, true)
    result = result..buildInfoboxRow("[[Noise Level]]", getValue(Weapon, "NoiseLevel", true), true)
    result = result..buildInfoboxRow("[[Accuracy]]", getValue(Weapon, "Accuracy"), true)
    result = result..buildInfoboxRow("[[Accuracy|Bullet Spread]]", Weapon.Spread, true)
    result = result..buildInfoboxRow("[[Recoil]]", Weapon.Recoil, true)
    result = result..buildInfoboxRow("[[Ammo#Magazine Capacity|Magazine Size]]", getValue(Weapon, "Magazine", false, true), nil)
    result = result..buildInfoboxRow("[[Ammo#Ammo Maximum|Max Ammo]]", getValue(Weapon, "MaxAmmo", true, true), true)
    result = result..buildInfoboxRow("[[Reload|Reload Time]]", getValue(Weapon, "Reload", false, true))
    result = result..buildInfoboxRow("[[Reload|Reload Rate]]", Weapon.RoundReload, nil, 2, " round<s>/sec")
    if(Weapon.Disposition ~= nil) then
        result = result..buildInfoboxRow("[[Riven Mods#Disposition|Disposition]]", Icon._Dis(Weapon.Disposition, "Text"))
    end
 
    if(hasAttack(Weapon, "Normal")) then
        result = result..makeAttackInfoboxRows(Weapon, Weapon, "Normal Attacks")
    end
    result = result..makeAttackInfoboxRows(Weapon, Weapon.AreaAttack, "AoE Attacks")
    result = result..makeAttackInfoboxRows(Weapon, Weapon.ChargeAttack, "[[Fire Rate#Charged Weapons|Charge Attacks]]")
    result = result..makeAttackInfoboxRows(Weapon, Weapon.SecondaryAttack, "Secondary Attacks")
 
 
 
    result = result..buildInfoboxCategory("Miscellaneous")
    if(Weapon.Zoom ~= nil) then
        result = result..buildInfoboxRow("[[Sniper Rifle|Zoom Levels]]", table.concat(Weap.Zoom, "<br/>"))
    end
    result = result..buildInfoboxRow("[[Sniper Rifle|Shot Combo Reset]]", Weapon.SniperComboReset)
    result = result..buildInfoboxRow("[[Sniper Rifle|Min. Shot Combo]]",Weapon.SniperComboMin)
    if(Weapon.SyndicateEffect ~= nil) then
        result = result..buildInfoboxRow("[[Syndicate Radial Effects|Syndicate Effect]]", "[["..Weapon.SyndicateEffect.."]]")
    end
 
    local augments = getAugments(Weapon)
    if(Shared.tableCount(augments) > 0) then
        local AugString = ""
        for i, Aug in pairs(augments) do
            if(i>1) then AugString = AugString.."<br/>" end
            AugString = AugString.."[["..Aug.Name.."]]"
        end
        result = result..buildInfoboxRow("[[Weapon Augment Mods|Augments]]", AugString)
    end
 
    result = result..buildInfoboxRow("[[Polarity|Polarities]]", GetPolarityString(Weapon))
 
    local canPvP = (getValue(Weapon, "Conclave", true)) and "Yes" or "No"
    result = result..buildInfoboxRow("[[Conclave]] Eligible", canPvP, true)
 
 
    if(Weapon.Users ~= nil) then
        local userString = ""
        --table.concat not working here because???
        --so doing it the hard way
        for i, User in pairs(Weapon.Users) do
            if(i>1) then userString = userString.."<br/>" end
            userString= userString..User
        end
        result = result..buildInfoboxRow("Weapon Users", userString)
    end
    result = result..buildInfoboxRow("Introduced", Weapon.Introduced)
 
    if(Weapon.Family ~= nil) then
        local FamilyString = ""
        local Family = getFamily(Weapon.Family)
        for i, Weap in pairs(Family) do
            if(Weap.Name ~= Weapon.Name) then
                if(string.len(FamilyString) > 0) then FamilyString = FamilyString.."<br/>" end
                FamilyString = FamilyString.."[["..Weap.Name.."]]"
            end
        end
        if(string.len(FamilyString) > 0) then
    result = result..buildInfoboxRow("Related Weapons", FamilyString)
        end
    end
 
    return result
end
 
function p.buildMeleeAutobox(frame)
    local WeapName = frame.args ~= nil and frame.args[1] or frame
    local Weapon = p.getWeapon(WeapName)
    if(Weapon == nil) then
        return buildInfoboxRow("ERROR", "Weapon not found in [[Module:Weapons/data]]")
    end
    local result = ""
    local imgFile = Weapon.Image ~= nil and Weapon.Image or "Panel.png"
 
    result = '\n|-\n| colspan="2" class="image" | [[File:'..imgFile..'|220px]]<br/>'
    result = result..buildInfoboxCategory("Statistics[[Category:Automatic Weapon Box]]")
    result = result..buildInfoboxRow("[[Mastery Rank]]", Weapon.Mastery)
    result = result..buildInfoboxRow("Weapon Slot", Weapon.Type)
    result = result..buildInfoboxRow("Weapon Type", linkMeleeClass(Weapon.Class))
 
 
 
    result = result..buildInfoboxCategory("Utility")
    if(Weapon.Bullet ~= nil) then
        result = result..buildInfoboxRow("[[Throwing Speed|Flight Speed]]", Weapon.Bullet.Speed, true, 2, " m/s")
        result = result..buildInfoboxRow("Range Limit", Weapon.Bullet.Range, true, 2, " m")
    end
    result = result..buildInfoboxRow("[[Attack Speed]]", Weapon.FireRate, nil)
    if(Weapon.Disposition ~= nil) then
        result = result..buildInfoboxRow("[[Riven Mods#Disposition|Disposition]]", Icon._Dis(Weapon.Disposition, "Text"))
    end
 
 
 
    result = result..buildInfoboxCategory("Normal Attacks")
    local Physical = GetDamage(Weapon, "Physical")
    if(Physical > 0) then
        result = result..buildInfoboxRow("[[Damage 2.0|Physical Damage]]", Physical, nil, {2, 1})
        result = result..buildInfoboxRow(Icon._Proc("Impact", "Text", "white", nil, true), GetDamage(Weapon, "Impact"), true, {2, 1})
        result = result..buildInfoboxRow(Icon._Proc("Puncture", "Text", "white", nil, true), GetDamage(Weapon, "Puncture"), true, {2, 1})
        result = result..buildInfoboxRow(Icon._Proc("Slash", "Text", "white", nil, true), GetDamage(Weapon, "Slash"), true, {2, 1})
    end
 
    for element, damage in Shared.skpairs(Weapon.Damage) do
        if(element ~= "Impact" and element ~= "Puncture" and element ~= "Slash") then
            result = result..buildInfoboxRow(Icon._Proc(element, "Text", "white", nil, true), damage, nil, {2, 1})
        end
    end
    result = result..buildInfoboxRow("Best Damage %", GetDamageBiasString(Weapon), true)
 
    result = result..buildInfoboxRow("[[Critical Hit#Critical Hit Chance|Crit Chance]]", asPercent(Weapon.CritChance))
    result = result..buildInfoboxRow("[[Critical Hit#Critical Damage Multiplier|Crit Multiplier]]", asMultiplier(Weapon.CritMultiplier))
    result = result..buildInfoboxRow("[[Status Chance]]", asPercent(Weapon.StatusChance))
 
    result = result..makeAttackInfoboxRows(Weapon, Weapon.ThrowAttack, "Throw Attacks")
    result = result..makeAttackInfoboxRows(Weapon, Weapon.ChargedThrowAttack, "Charged Throw Attacks")
 
    if(Weapon.JumpAttack ~= nil)then
        result = result..buildInfoboxCategory("[[Melee 2.0#Slam Attack|Slam Attacks]]")
        if(Weapon.JumpElement ~= nil) then
            result = result..buildInfoboxRow(Icon._Proc(Weapon.JumpElement, "text", "white", nil, true), Weapon.JumpAttack)
        else
            result = result..buildInfoboxRow("[[Damage 2.0|Physical Damage]]", Weapon.JumpAttack)
        end
        result = result..buildInfoboxRow("Radius", Weapon.JumpRadius, nil, 2, "m")
    end
 
    if(Weapon.SlideAttack ~= nil)then
        result = result..buildInfoboxCategory("[[Melee 2.0#Slide Attack|Slide Attacks]]")
        if(Weapon.SlideElement ~= nil) then
            result = result..buildInfoboxRow(Icon._Proc(Weapon.SlideElement, "text", "white", nil, true), Weapon.SlideAttack)
        else
            result = result..buildInfoboxRow("[[Damage 2.0|Physical Damage]]", Weapon.SlideAttack)
        end
    end
 
    if(Weapon.WallAttack ~= nil)then
        result = result..buildInfoboxCategory("[[Melee 2.0#Wall Attack|Wall Attacks]]")
        if(Weapon.WallElement ~= nil) then
            result = result..buildInfoboxRow(Icon._Proc(Weapon.WallElement, "text", "white", nil, true), Weapon.WallAttack)
        else
            result = result..buildInfoboxRow("[[Damage 2.0|Physical Damage]]", Weapon.WallAttack)
        end
    end
 
    result = result..buildInfoboxCategory("Miscellaneous")
    result = result..buildInfoboxRow("[[Melee 2.0#Ground Finisher|Finisher Damage]]", Weapon.FinisherDamage, true)
    result = result..buildInfoboxRow("Stagger", Weapon.Stagger)
 
    local augments = getAugments(Weapon)
    if(Shared.tableCount(augments) > 0) then
        local AugString = ""
        for i, Aug in pairs(augments) do
            if(i>1) then AugString = AugString.."<br/>" end
            AugString = AugString.."[["..Aug.Name.."]]"
        end
        result = result..buildInfoboxRow("[[Weapon Augment Mods|Augments]]", AugString)
    end
 
    result = result..buildInfoboxRow("[[Polarity|Polarities]]", GetPolarityString(Weapon))
    result = result..buildInfoboxRow("[[Stance]]", getWeaponStanceList(Weapon))
    if(Weapon.StancePolarity ~= nil) then
        result = result..buildInfoboxRow("[[Stance]] [[Polarity]]", Icon._Pol(Weapon.StancePolarity))
    end
 
 
    local canPvP = (getValue(Weapon, "Conclave", true)) and "Yes" or "No"
    result = result..buildInfoboxRow("[[Conclave]] Eligible", canPvP, true)
    if(Weapon.Users ~= nil) then
        local userString = ""
        --table.concat not working here because???
        --so doing it the hard way
        for i, User in pairs(Weapon.Users) do
            if(i>1) then userString = userString.."<br/>" end
            userString= userString..User
        end
        result = result..buildInfoboxRow("Weapon Users", userString)
    end
    result = result..buildInfoboxRow("Introduced", Weapon.Introduced)
 
    if(Weapon.Family ~= nil) then
        local FamilyString = ""
        local Family = getFamily(Weapon.Family)
        for i, Weap in pairs(Family) do
            if(Weap.Name ~= Weapon.Name) then
                if(string.len(FamilyString) > 0) then FamilyString = FamilyString.."<br/>" end
                FamilyString = FamilyString.."[["..Weap.Name.."]]"
            end
        end
        if(string.len(FamilyString) > 0) then
    result = result..buildInfoboxRow("Related Weapons", FamilyString)
        end
    end
 
    return result
end
 
function p.buildAugmentTable(frame)
    local result = ""
    result = result..'\n{|class="listtable sortable" style="width:100%;"'
    result = result..'\n|-'
    result = result..'\n! Name'
    result = result..'\n! Category'
    result = result..'\n! Source'
    result = result..'\n! Weapon'
 
    for i, Augment in pairs(WeaponData["Augments"]) do
        local thisStr = "\n|-"
        thisStr = thisStr.."\n| [["..Augment.Name.."]]"
        thisStr = thisStr.."\n| "..Augment.Category
        thisStr = thisStr.."\n| [["..Augment.Source.."]]"
        thisStr = thisStr.."\n| "
        for i, weap in pairs(Augment.Weapons) do
            if(i>1) then thisStr = thisStr.."<br/>" end
            thisStr = thisStr.."[["..weap.."]]"
        end
        result = result..thisStr
    end
 
    result = result..'\n|}'
    return result 
end
 
function noNil(val, default)
    if(val ~= nil) then
        return val
    else
        if(default ~= nil) then
            return default
        else
            return ""
        end
    end
end
 
function p.buildDamageTypeTable(frame)
    local DamageType = frame.args ~= nil and frame.args[1] or frame
    local Weapons = {}
    local WeapArray = getWeapons(function(x) 
                                    local Dmg, Element = GetDamageBias(x)
                                    return Element == DamageType end)
 
    local procString = Icon._Proc(DamageType,'text')
    local procShort = Icon._Proc(DamageType)
    local result = ""
    local tHeader = '{|class = "listtable sortable" style="margin:auto;"'
    tHeader = tHeader..'\n|-'
    tHeader = tHeader..'\n!Name'
    tHeader = tHeader..'\n!Type'
    tHeader = tHeader..'\n!Class'
    tHeader = tHeader..'\n!'..procString
    tHeader = tHeader..'\n!'..procShort..'%'
    local tRows = ""
    for i, Weapon in pairs(WeapArray) do
        local thisRow = '\n|-\n|'
        thisRow = thisRow.."[["..Weapon.Name.."]]||"..Weapon.Type.."||"..noNil(Weapon.Class, "?")
        thisRow = thisRow.."||"..Weapon.Damage[DamageType].."||"..GetDamageBiasString(Weapon, true)
 
        tRows = tRows..thisRow
    end
    result = tHeader..tRows.."\n|}"
    return result
end
 
function p.buildWeaponByMasteryRank(frame)
    local MasteryRank
    local MRTable = {}
    for i, Weapon in Shared.skpairs(WeaponData["Weapons"]) do
        if(MRTable[Weapon.Mastery] == nil) then
            MRTable[Weapon.Mastery] = {}
        end
        if(MRTable[Weapon.Mastery][Weapon.Type] == nil) then
            MRTable[Weapon.Mastery][Weapon.Type] = {}
        end
        table.insert(MRTable[Weapon.Mastery][Weapon.Type], Weapon)
    end
    local result = ""
    for i, TypeTable in Shared.skpairs(MRTable) do
        local thisTable = "\n==Mastery Rank "..i.." Required=="
        if(i == 0) then
            thisTable = "==No Mastery Rank Required=="
        end
        thisTable = thisTable..'\n{| style="width:80%;margin:auto"'
        thisTable = thisTable..'\n|-\n| style="vertical-align:top;width:33%;" |'
        if(TypeTable["Primary"] ~= nil and Shared.tableCount(TypeTable["Primary"]) > 0) then
            thisTable = thisTable.."\n===Primary==="
            for i, Weap in Shared.skpairs(TypeTable["Primary"]) do
                thisTable = thisTable.."\n* [["..Weap.Name.."]]"
            end
        end
 
        thisTable = thisTable..'\n| style="vertical-align:top;width:33%;" |'
        if(TypeTable["Secondary"] ~= nil and Shared.tableCount(TypeTable["Secondary"]) > 0) then
            thisTable = thisTable.."\n===Secondary==="
            for i, Weap in Shared.skpairs(TypeTable["Secondary"]) do
                thisTable = thisTable.."\n* [["..Weap.Name.."]]"
            end
        end
 
        thisTable = thisTable..'\n| style="vertical-align:top;width:33%;" |'
        if(TypeTable["Melee"] ~= nil and Shared.tableCount(TypeTable["Melee"]) > 0) then
            thisTable = thisTable.."\n===Melee==="
            for i, Weap in Shared.skpairs(TypeTable["Melee"]) do
                thisTable = thisTable.."\n* [["..Weap.Name.."]]"
            end
        end
        thisTable = thisTable.."\n|}"
        result = result..thisTable
    end
    return result
end
 
--Runs a bunch of things to quickly check if anything broke
function p.checkForBugs(frame)
    return p.buildComparison({args = {"Lato", "Lato Prime"}})..p.buildComparison({args = {"Glaive", "Glaive Prime"}})..p.buildAutobox("Dread")..p.buildAutobox("Cerata")
end
 
function p.checkElements(frame)
    local result = "wyrd"
    for key, theWeap in Shared.skpairs(WeaponData["Weapons"]) do
        for attName, Attack in p.attackLoop(theWeap) do
            local elementCount = 0
            if(Attack.Damage ~= nil) then
                for element, dmg in Shared.skpairs(Attack.Damage) do
                    if(not Shared.contains(Physical, element)) then
                        elementCount = elementCount + 1
                    end
                end
            else
                result = result.."\n"..key.." attempted to loop the "..attName.." attack"
            end
            if(elementCount > 1) then
                result = result.."\n"..key.." has "..elementCount.." elements in its "..attName.." attack"
            end
        end
    end
    return result
end
 
function p.checkForMissingData(frame)
    local result = ""
    for key, weapon in Shared.skpairs(WeaponData["Weapons"]) do
        if(weapon.Name == nil) then
            result = result.."\n"..key.." does not have a Name"
        end
        if(weapon.Image == nil) then
            result = result.."\n"..key.." does not have an Image"
        end
        if(weapon.Mastery == nil) then
            result = result.."\n"..key.." does not have Mastery"
        end
        if(weapon.Disposition == nil) then
            result = result.."\n"..key.." does not have Disposition"
        end
        if(weapon.Type == nil) then
            result = result.."\n"..key.." does not have a Type"
        end
        if(weapon.Class == nil) then
            result = result.."\n"..key.." does not have a Class"
        end
        if(weapon.Damage == nil) then
            result = result.."\n"..key.." does not do Normal Attacks"
        end
    end
    if (result == "") then
        result = "All weapons complete based on this test"
    end
    return result
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.