FANDOM


--This will eventually contain data for various weapons --For use in automating assorted wiki functions and to reduce the number of updates needed -- •

local p = {}

local WeaponData = mw.loadData( 'Module:Weapons/data' ) local ConclaveData = mw.loadData( 'Module:Weapons/Conclave/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", "CHANNELMULT"} local VariantList = {"Prime", "Prisma", "Wraith", "Vandal", "Vaykor", "Synoid", "Telos", "Secura", "Sancti", "Rakta", "Mara", "MK1"}

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.isVariant(WeapName)

   for i, var in pairs(VariantList) do
       if(string.find(WeapName, var)) then
           local baseName = string.gsub(WeapName, ' ?'..var..' ?-?', )
           return true, var, baseName
       end
   end
   return false, 'Base', WeapName

end

function p.buildName(BaseName, Variant)

   if(Variant == nil or Variant == 'Base' or Variant == ) then
       return BaseName
   elseif(Variant == 'Prime' or Variant == 'Wraith' or Variant == 'Vandal') then
       return BaseName..' '..Variant
   elseif(Variant == "MK1") then
       return "MK1-"..BaseName
   else
       return Variant..' '..BaseName
   end

end

--It's a bit of a mess, but this is for compressing a list with variants --So if a list has Braton, Braton Prime, and MK1-Braton it'll list as -- Braton (MK1, Prime) function p.shortLinkList(Weapons)

   --First grabbing all the pieces and stashing them in a table
   local baseNames = {}
   for key, weap in Shared.skpairs(Weapons) do
       local isVar, varType, baseName = p.isVariant(weap.Name)
       if(baseNames[baseName] == nil) then baseNames[baseName] = {} end
       table.insert(baseNames[baseName], varType)
   end
   
   --Then the fun part: Pulling the table together
   local result = {}
   for baseName, variants in Shared.skpairs(baseNames) do
       --So first, check if 'Base' is in the list
       --Because if it isn't, list all variants separately
       if(Shared.contains(variants, "Base")) then
           table.sort(variants)
           --First, get the basic version
           local thisRow = ''..baseName..""
           --then, if there are variants...
           if(Shared.tableCount(variants) > 1) then
               --List them in parentheses one at a time
               thisRow = thisRow..' ('
               local count = 0
               for i, varName in pairs(variants) do
                   if(varName ~= 'Base') then
                       if(count > 0) then thisRow = thisRow..', ' end
                       thisRow = thisRow..''..varName..''
                       count = count + 1
                   end
               end
               thisRow = thisRow..')'
           end
           table.insert(result, thisRow)
       else
           for i, varName in pairs(variants) do
               table.insert(result, ''..p.buildName(baseName, varName)..'')
           end
       end
   end
   return result

end

function p.test()

   local shortList = p.shortLinkList(WeaponData["Weapons"])
   local result = 
   for i, val in pairs(shortList) do
       result = result..'\n'..val
   end
   return result

end

function p.getWeapon(WeapName)

   if WeaponData["Weapons"][WeapName] then
       local weapon = WeaponData["Weapons"][WeapName]
       if weapon.Name == WeapName then
           return weapon
       end
   else
       for key, Weapon in Shared.skpairs(WeaponData["Weapons"]) do
           if(Weapon.Name == WeapName or key == WeapName) then
               return Weapon            
           end
       end
   end
   return nil

end

function p.weaponExists(frame)

   local WeapName = frame.args ~= nil and frame.args[1]
   if WeapName == 'Dark Split-Sword' and frame.args[2] == 'true' then
       return true
   end
   
   if p.getWeapon(WeapName) then
       return true
   end
   
   return 'No weapon '..WeapName..' found.'

end

function p.getConclaveWeapon(WeapName)

   for key, Weapon in Shared.skpairs(ConclaveData["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

function p.isArchwing(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 == "Arch-Gun" 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.NormalAttack ~= nil) then
           return Weapon.NormalAttack
       elseif(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 true 
   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 ""..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((weap.Ignore == nil or not weap.Ignore) and weap.Type ~= nil and weap.Type == "Melee") 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

--As above, but for Conclave stats local function getConclaveMeleeWeapons(weapClass, PvP)

   local weaps = {}
   local weapClasses = {}
   if(weapClass ~= nil) then
       weapClasses = Shared.splitString(weapClass, ',')
   end
   
   for i, weap in Shared.skpairs(ConclaveData["Weapons"]) do
       if((weap.Ignore == nil or not weap.Ignore) and weap.Type ~= nil and weap.Type == "Melee") 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 function p.getWeapons(validateFunction)

   local weaps = {}
   for i, weap in Shared.skpairs(WeaponData["Weapons"]) do
       if((weap.Ignore == nil or not weap.Ignore) and validateFunction(weap)) then
           table.insert(weaps, weap)
       end
   end
   return weaps

end

--Same as getWeapons, but for Conclave data function p.getConclaveWeapons(validateFunction)

   local weaps = {}
   for i, weap in Shared.skpairs(ConclaveData["Weapons"]) do
       if((weap.Ignore == nil or not weap.Ignore) and 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(Attack, Type, ByPellet)

   if(ByPellet == nil) then ByPellet = false end
   if(Attack == nil or Attack.Damage == nil) then return 0 end
   
   local pCount = 1
   if(ByPellet and Attack.PelletCount ~= nil) then pCount = Attack.PelletCount end
   if(Type == nil) then
       local total = 0
           for i, d in Shared.skpairs(Attack.Damage) do
               total = total + d
           end
       return total / pCount
   else
       if(Type == "Physical") then
           local Impact = Attack.Damage["Impact"] ~= nil and Attack.Damage["Impact"] or 0
           local Puncture = Attack.Damage["Puncture"] ~= nil and Attack.Damage["Puncture"] or 0
           local Slash = Attack.Damage["Slash"] ~= nil and Attack.Damage["Slash"] or 0
           return (Impact + Puncture + Slash) / pCount
       elseif(Type == "Element") then
           for dType, dmg in Shared.skpairs(Attack.Damage) do
               if(not Shared.contains(Physical, dType) or dmg <= 0) then
                   return dmg / pCount
               end
           end
           return 0
       elseif(Attack.Damage[Type] == nil) then
           return 0
       else
           return Attack.Damage[Type] / pCount
       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(Attack, Type, ByPellet)

   if(ByPellet == nil) then ByPellet = false end
   if(Attack == nil or Attack.Damage == nil) then return "" end
   
   local pCount = 1
   if(ByPellet and Attack.PelletCount ~= nil) then pCount = Attack.PelletCount end
   if(Type == nil) then
       if(not hasMultipleTypes(Attack)) then
           for key, val in pairs(Attack.Damage) do
               if(val > 0) then
                   return Icon._Proc(key).." "..Shared.round(val / pCount, 2)
               end
           end
           return ""
       else
           return Shared.round(GetDamage(Attack, nil, ByPellet), {2, 1})
       end
   else
       local thisVal = GetDamage(Attack, Type, ByPellet)
       if(thisVal == 0) then
           return ""
       else
           return Shared.round(thisVal, {2, 1})
       end
   end

end

local function GetDamageBias(Attack, IncludeSingle)

   if(IncludeSingle == nil) then IncludeSingle = false end
   
   if(Attack.Damage ~= nil and Shared.tableCount(Attack.Damage) > 0) 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
       --Exception for physical damage types
       if(count > 1 or (IncludeSingle and count > 0)) 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, IncludeSingle, Color)

   if(HideType == nil) then HideType = false end
   if(ShowText == nil) then ShowText = "" end
   if(IncludeSingle == nil) then IncludeSingle = false end
   
   local bestPercent, bestElement = GetDamageBias(Attack, IncludeSingle)
   if(bestPercent ~= nil) then
       local result = asPercent(bestPercent, 0)
       if(not HideType) then
           result = Icon._Proc(bestElement, ShowText, Color).." "..result
       end
       return result
   else
       return nil
   end

end

function p.GetPolarityString(Weapon)

   if(Weapon.Polarities == nil or type(Weapon.Polarities) ~= "table" 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)

   if(Weapon == nil or Weapon.Type ~= "Melee") then return nil end
   
   local stances = getStances(Weapon.Class, Weapon.Conclave)
   
   local result = ""
   
   for i, stance in pairs(stances) do
       if (string.len(result) > 0) then
           result = result.."
" 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, forTable)

   if(giveDefault == nil) then giveDefault = false end
   if(asString == nil) then asString = false end
   if(forTable == nil) then forTable = 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 == "ACCURACY") then
       if(Attack.Accuracy ~= nil) then
           return Attack.Accuracy
       elseif(Attack == Weapon.NormalAttack) then
           return Weapon.Accuracy
       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 == "AMMOCOST") then
       if(Attack.AmmoCost ~= nil) then
           if(asString) then
               return Attack.AmmoCost.." ammo per shot"
           else
               return Attack.AmmoCost
           end
       elseif(giveDefault) then
           return 1
       else
           return nil
       end
   elseif(ValName == "BURSTCOUNT") then
       if(Attack.BurstCount ~= nil) then
           if(asString) then
               local result = Attack.BurstCount.." rounds"
               local dmg = GetDamage(Attack) * Attack.BurstCount
               return result.." ("..Shared.round(dmg, 2, 1).." total damage)"
           else
               return Attack.BurstCount
           end
       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 -- note there is getValue version
   --search in current attack, then normal, 
       if(Attack.CritChance ~= nil) then
           if(asString) then
               return asPercent(Attack.CritChance)
           else
               return Attack.CritChance
           end
       end
       if(hasAttack(Weapon, "Normal")) then
           local normAtt = getAttack(Weapon, "Normal")
           if(normAtt.CritChance ~= nil) then
               if(asString) then
                   return asPercent(normAtt.CritChance)
               else
                   return normAtt.CritChance
               end
           end
       end
       if giveDefault then
           if(asString) then
               return asPercent(0)
           else
               return 0
           end
       else
           return nil
       end
   elseif(ValName == "CRITMULTIPLIER") then -- note there is getValue version
   --search in current attack, then normal, 
       if(Attack.CritMultiplier ~= nil) then
           if(asString) then
               return asMultiplier(Attack.CritMultiplier)
           else
               return Attack.CritMultiplier
           end
       end
       if(hasAttack(Weapon, "Normal")) then
           local normAtt = getAttack(Weapon, "Normal")
           if(normAtt.CritMultiplier ~= nil) then
               if(asString) then
                   return asMultiplier(normAtt.CritMultiplier)
               else
                   return normAtt.CritMultiplier
               end
           end
       end
       if giveDefault then
           if(asString) then
               return asMultiplier(0)
           else
               return 0
           end
       else
           return nil
       end
   elseif(ValName == "DAMAGEBIAS") then
       if(Shared.tableCount(Attack.Damage) <= 3) then
           return GetDamageBiasString(Attack, nil, nil, giveDefault)
       else
           if(asString) then
               return ""
           else
               return nil
           end
       end
   elseif(ValName == "BULLETTYPE") then
       if(Attack.ShotType ~= nil) then
           return Attack.ShotType
       elseif(giveDefault) then
           return "Unknown"
       else
           return nil
       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.."
Min damage at "..Shared.round(Attack.Falloff.EndRange, 2, 1).." m" if(Attack.Falloff.Reduction ~= nil) then falloffText = falloffText.."
"..asPercent(Attack.Falloff.Reduction).." max reduction" end return falloffText else return nil end elseif(ValName == "FIRERATE") then --search in current attack, then normal, then weapon supertable local returnVal = 0 if(Attack.FireRate ~= nil) then returnVal = Attack.FireRate elseif(hasAttack(Weapon, "Normal")) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.FireRate ~= nil) then returnVal = normAtt.FireRate end elseif(Weapon.FireRate ~= nil) then returnVal = Weapon.FireRate end if(asString) then if(Weapon.Type ~= nil and Weapon.Type ~= "Melee" and Weapon.Type ~= "Arch-Melee") then if(forTable) then return Shared.round(returnVal, {3, 1}) -- .." rps" else return Shared.round(returnVal, {3, 1})..p.doPlural(" round per sec", returnVal) end else return Shared.round(returnVal, {3, 1}) end else return returnVal end if (giveDefault) then returnVal = 0 else return nil end elseif(ValName == "NOISELEVEL") then if(Attack.NoiseLevel ~= nil) then return Attack.NoiseLevel else return nil end elseif(ValName == "PELLETCOUNT") then if(Attack.PelletCount ~= nil) then if(asString) then if(Attack.PelletName ~= nil) then return Attack.PelletCount.." "..Attack.PelletName.."s" else return Attack.PelletCount.." Pellets" end else return Attack.PelletCount end elseif giveDefault then return 0 else return nil end elseif(ValName == "PELLETDAMAGE") then if(Attack.PelletCount ~= nil) then local result = GetDamageString(Attack, nil, true) if(Attack.PelletName ~= nil) then return result.." per "..string.lower(Attack.PelletName) else return result.." per pellet" end else return nil end elseif(ValName == "PELLETNAME") then if(Attack.PelletCount ~= nil) then if(Attack.PelletName ~= nil) then return Attack.PelletName else return "Pellet" end else return nil end elseif(ValName == "PELLETPLUS") then if(Attack.PelletCount ~= nil) then local result = Attack.PelletCount.." (" result = result..Shared.round(GetDamage(Attack, nil, true), 2, 1) if(Attack.PelletName ~= nil) then return result.." damage per "..string.lower(Attack.PelletName)..")" else return result.." damage per pellet)" end else return nil end elseif(ValName == "PROJECTILESPEED") then if(Attack.ShotSpeed ~= nil) then if(asString) then return Attack.ShotSpeed.." m/s" else return Attack.ShotSpeed 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.Range ~= nil) then if(asString) then return Attack.Range.." m" else return Attack.Range end elseif(giveDefault) then if(asString) then return "0 m" else return 0 end else return nil end elseif(ValName == "RELOAD") then --man screw you too Fusilai if(Attack.Reload ~= nil) then if(asString) then return Shared.round(Attack.Reload, 2, 1).." s" else return Attack.Reload end elseif giveDefault then return 0 else return nil end elseif(ValName == "SPOOL") then if(Attack.Spool ~= nil) then if(asString) then return Attack.Spool.." rounds" else return Attack.Spool end else return nil end elseif(ValName == "STANCES") then return getWeaponStanceList(Weapon) elseif(ValName == "STATUSCHANCE") then -- search in current attck, then normal if(Attack.StatusChance ~= nil) then if(asString) then return asPercent(Attack.StatusChance) else return Attack.StatusChance end end if(hasAttack(Weapon, "Normal")) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.StatusChance ~= nil) then if(asString) then return asPercent(normAtt.StatusChance) else return normAtt.StatusChance end end end if giveDefault then if(asString) then return asPercent(0) else return 0 end else return nil end elseif(ValName == "TRIGGER") then -- use getValue for tables -- search in current attack, then weapon supertable if(Attack.Trigger ~= nil) then return Attack.Trigger end if(Weapon.Trigger ~= nil) then return Weapon.Trigger end if giveDefault then return "Unknown" else return nil end else return "ERROR: No such value "..ValName end

end

local function getValue(Weapon, ValName, giveDefault, asString, forTable)

   if(giveDefault == nil) then giveDefault = false end
   if(asString == nil) then asString = false end
   if(forTable == nil) then forTable = 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, getAttack(Weapon, "Normal"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "AREA" or VName1 == "AREAATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "Area"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "SECONDARYAREA" or VName1 == "SECONDARYAREAATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "SecondaryArea"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "CHARGE" or VName1 == "CHARGEATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "Charge"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "CHARGEDTHROW" or VName1 == "CHARGEDTHROWATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "ChargedThrow"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "THROW" or VName1 == "THROWATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "Throw"), VName2, giveDefault, asString, forTable)
       elseif(VName1 == "SECONDARY" or VName1 == "SECONDARYATTACK") then
           return getAttackValue(Weapon, getAttack(Weapon, "Secondary"), VName2, giveDefault, asString, forTable)
       else
           return "ERROR: No such attack '"..VName1.."'"
       end
   end
   
   ValName = string.upper(ValName)
   if(ValName == "NAME") then
       if(Weapon.Name ~= nil) then
           if(forTable) then 
               return ""..Weapon.Name..""
           else
               return Weapon.Name
           end
       elseif giveDefault then
           return ""
       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 Rifle" 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.."
" end AugString = AugString..""..Aug.Name.."" end return AugString else return nil end elseif(ValName == "BLOCKRESIST") then if(Weapon.Class ~= nil) then if(Weapon.Type == "Melee") then if(Weapon.BlockResist ~= nil) then if(asString) then return asPercent(Weapon.BlockResist) else return Weapon.BlockResist end elseif(Weapon.Class == "Claws" or Weapon.Class == "Dagger" or Weapon.Class == "Dual Daggers" or Weapon.Class == "Glaive" or Weapon.Class == "Nunchaku" or Weapon.Class == "Rapier" or Weapon.Class == "Sparring" or Weapon.Class == "Tonfa" or Weapon.Class == "Whip") then if(asString) then return "35%" else return .35 end elseif(Weapon.Class == "Blade and Whip" or Weapon.Class == "Dual Swords" or Weapon.Class == "Fist" or Weapon.Class == "Gunblade" or Weapon.Class == "Staff" or Weapon.Class == "Sword") then if(asString) then return "60%" else return .6 end elseif(Weapon.Class == "Hammer" or Weapon.Class == "Heavy Blade" or Weapon.Class == "Machete" or Weapon.Class == "Nikana" or Weapon.Class == "Polearm" or Weapon.Class == "Scythe" or Weapon.Class == "Sword and Shield") then if(asString) then return "85%" else return .85 end end else return "" end else return "" end elseif(ValName == "CHANNELMULT") then if(Weapon.ChannelMult ~= nil) then if(asString) then return asMultiplier(Weapon.ChannelMult) else return Weapon.ChannelMult end elseif giveDefault and (Weapon.Type ~= nil and Weapon.Type == "Melee") 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 ""..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.Type ~= nil and (Weapon.Type == "Arch-Gun" or Weapon.Type == "Arch-Melee") or Weapon.Type == "Emplacement") then return nil end 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 if(asString) then 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.."
" end FamilyString = FamilyString..""..Weap.Name.."" end end return FamilyString end else return Weapon.Family end 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 if (forTable) then return Weapon.Magazine else return Weapon.Magazine..p.doPlural(" round<s> per mag", Weapon.Magazine) end else return Weapon.Magazine end elseif giveDefault then if(asString) then return "0 rounds per 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 Rifle") 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" and Weapon.Type ~= "Arch-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 and type(Weapon.Polarities) == "table") then if(asString) then return p.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 if(Weapon.ReloadStyle ~= nil) then if(Weapon.ReloadStyle == "ByRound" and Weapon.Magazine ~= nil) then local result = Shared.round(Weapon.Reload / Weapon.Magazine, 2, 1).." sec per round" result = result.." ("..Shared.round(Weapon.Reload, 2, 1).."s total)" if(forTable) then result = Shared.round(Weapon.Reload, 2, 1).." s" end return result elseif(Weapon.ReloadStyle == "Regenerate") then local result = Shared.round(Weapon.Reload, 2, 1).." rounds per sec" if(Weapon.Magazine ~= nil) then result=result.." ("..Shared.round(Weapon.Magazine / Weapon.Reload, 2, 1).."s total)" if(forTable) then result=Shared.round(Weapon.Magazine / Weapon.Reload, 2, 1).." s" end end return result end end 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 == "TRIGGER") then -- Note there is a specific version for each attack in getAttackValue if(Weapon.Trigger ~= nil) then if (forTable) then -- return chargetime and burstcount only in tables local trigger = Weapon.Trigger if(trigger == "Charge") then local cTime = getAttackValue(Weapon, getAttack(Weapon,"Charge"), "ChargeTime", false) if(cTime ~= nil) then return trigger.." ("..Shared.round(cTime, 2, 1).."s)" else return trigger end elseif(trigger == "Burst") then local bCount = getAttackValue(Weapon, getAttack(Weapon,"Normal"), "BurstCount", false) if(bCount ~= nil) then return trigger.." ("..bCount..")" else return trigger end else return trigger end else return Weapon.Trigger end elseif giveDefault then return "Unknown" else return nil end elseif(ValName == "CRITCHANCE") then -- Note there is a specific version for each attack in getAttackValue -- search in charge attck, then normal, then secondary if still null local returnVal=0 local Attack={} if(hasAttack(Weapon, "Charge")) then local chargAtt = getAttack(Weapon, "Charge") if(chargAtt.CritChance ~= nil) then returnVal=chargAtt.CritChance Attack=chargAtt end end if(hasAttack(Weapon, "Normal") and returnVal ==0) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.CritChance ~= nil) then returnVal=normAtt.CritChance Attack=normAtt end end if(hasAttack(Weapon, "Secondary") and returnVal ==0) then local secAtt = getAttack(Weapon, "Secondary") if(secAtt.CritChance ~= nil) then returnVal=secAtt.CritChance Attack=secAtt end end if(asString and returnVal ~= 0) then return asPercent(returnVal) else return returnVal end if giveDefault then return 0 else return nil end elseif(ValName == "CRITMULTIPLIER") then--Note there is a specific version for each attack in getAttackValue -- search in charge attck, then normal, then secondary if still null local returnVal=0 local Attack={} if(hasAttack(Weapon, "Charge")) then local chargAtt = getAttack(Weapon, "Charge") if(chargAtt.CritMultiplier ~= nil) then returnVal=chargAtt.CritMultiplier Attack=chargAtt end end if(hasAttack(Weapon, "Normal") and returnVal ==0) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.CritMultiplier ~= nil) then returnVal=normAtt.CritMultiplier Attack=normAtt end end if(hasAttack(Weapon, "Secondary") and returnVal ==0) then local secAtt = getAttack(Weapon, "Secondary") if(secAtt.CritMultiplier ~= nil) then returnVal=secAtt.CritMultiplier Attack=secAtt end end if(asString and returnVal ~= 0) then return asMultiplier(returnVal) else return returnVal end if giveDefault then return 0 else return nil end elseif(ValName == "FIRERATE") then -- Note there is a specific version for each attack in getAttackValue -- search in global weapon then normal attck, then charge, then secondary if still null local returnVal=0 local Attack={} if(Weapon.FireRate ~= nil) then returnVal = Weapon.FireRate end if(hasAttack(Weapon, "Normal") and returnVal ==0) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.FireRate ~= nil) then returnVal=normAtt.FireRate Attack=normAtt end end if(hasAttack(Weapon, "Charge") and returnVal ==0) then local chargAtt = getAttack(Weapon, "Charge") if(chargAtt.FireRate ~= nil) then returnVal=chargAtt.FireRate Attack=chargAtt end end if(hasAttack(Weapon, "Secondary") and returnVal ==0) then local secAtt = getAttack(Weapon, "Secondary") if(secAtt.FireRate ~= nil) then returnVal=secAtt.FireRate Attack=secAtt end end if(asString and returnVal ~= 0) then if(Weapon.Type ~= nil and Weapon.Type ~= "Melee" and Weapon.Type ~= "Arch-Melee") then if(forTable) then return Shared.round(returnVal, {3, 1}) -- .." rps" else return Shared.round(returnVal, {3, 1})..p.doPlural(" round<s> per sec", returnVal) end else return Shared.round(returnVal, {3, 1}) end else return returnVal end if giveDefault then return 0 else return nil end elseif(ValName == "STATUSCHANCE") then -- Note there is a specific version for each attack in getAttackValue -- search in charge attck, then normal, then secondary if still null local returnVal=0 local Attack={} if(hasAttack(Weapon, "Charge")) then local chargAtt = getAttack(Weapon, "Charge") if(chargAtt.StatusChance ~= nil) then returnVal=chargAtt.StatusChance Attack=chargAtt end end if(hasAttack(Weapon, "Normal") and returnVal ==0) then local normAtt = getAttack(Weapon, "Normal") if(normAtt.StatusChance ~= nil) then returnVal=normAtt.StatusChance Attack=normAtt end end if(hasAttack(Weapon, "Secondary") and returnVal ==0) then local secAtt = getAttack(Weapon, "Secondary") if(secAtt.StatusChance ~= nil) then returnVal=secAtt.StatusChance Attack=secAtt end end if(asString and returnVal ~= 0) then return asPercent(returnVal) else return returnVal end if giveDefault then return 0 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..'
' 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..'
' end result = result..str end return result else return Weapon.Zoom end else return nil end elseif(ValName == "SPECIALFSPEED") then -- to show we can put very special keywords... if wanted if(Weapon.Name == "Drakgoon") then if(asString) then return "bounce: 25 m/s" else return 25 end elseif(getAttackValue(Weapon,getAttack(Weapon,"Area"),"PROJECTILESPEED")~=nil) then if(asString) then return getAttackValue(Weapon,getAttack(Weapon,"Area"),"PROJECTILESPEED",true,true) else return getAttackValue(Weapon,getAttack(Weapon,"Area"),"PROJECTILESPEED") end elseif(getAttackValue(Weapon,getAttack(Weapon,"Secondary"),"PROJECTILESPEED")~=nil) then if(asString) then return getAttackValue(Weapon,getAttack(Weapon,"Secondary"),"PROJECTILESPEED",true,true) else return getAttackValue(Weapon,getAttack(Weapon,"Secondary"),"PROJECTILESPEED") end elseif(giveDefault) then if(asString) then return "0 m/s" else return 0 end else return nil end else --if everything failed (and it should NOT) try in the getAttackValue return getAttackValue(Weapon, getAttack(Weapon, "Normal"), ValName, giveDefault, asString) end

end

function p.getValue(frame)

   local WeapName = frame.args[1]
   local ValName1 = frame.args[2]
   local ValName2 = frame.args[3]
   local AsString = frame.args["Raw"] == nil
   if(WeapName == nil) then
       return ""
   elseif(ValName1 == nil) then
       return "ERROR: No value selected"
   end
   
   local theWeap = p.getWeapon(WeapName)
   if(theWeap == nil) then
       return ""
   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, AsString)

end

function p.getConclaveValue(frame)

   local WeapName = frame.args[1]
   local ValName1 = frame.args[2]
   local ValName2 = frame.args[3]
   if(WeapName == nil) then
       return ""
   elseif(ValName1 == nil) then
       return "ERROR: No value selected"
   end
   
   local theWeap = p.getConclaveWeapon(WeapName)
   if(theWeap == nil) then
       return ""
   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 = 
   result = '\n|-\n| style = "'..styleString..'"|'..Weapon.Name..""
   local attName = ""
   if(hasAttack(Weapon, "Charge")) then
       attName = "Charge"
   elseif(hasAttack(Weapon, "Normal")) then
       attName = "Normal"
   else
       return ""
   end
   
   local trigger = getValue(Weapon, "Trigger")
   result = result..td..trigger
   if(trigger == "Charge") then
       local cTime = getValue(Weapon, {attName, "ChargeTime"})
       if(cTime ~= nil) then
           result = result.." ("..Shared.round(cTime, 2, 1).."s)" 
       end
   elseif(trigger == "Burst") then
       local bCount = getValue(Weapon, {attName, "BurstCount"})
       if(bCount ~= nil) then
           result = result.." ("..bCount..")" 
       end
   end
   
   result = result..'||data-sort-value="'..getValue(Weapon, {attName, "Damage"})..'" style="'..styleString..'"|'..getValue(Weapon, {attName, "Damage"}, false, true)
   result = result..td..getValue(Weapon, {attName, "CritChance"}, true, true)..td..getValue(Weapon, {attName, "CritMultiplier"}, true, true)
   result = result..td..asPercent(getValue(Weapon, {attName, "StatusChance"}, true))
   result = result..td..getValue(Weapon,{attName, "BulletType"},true)
   result = result..td..Shared.round(getValue(Weapon, {attName, "FireRate"}, true), 3, 1)..td..Weapon.Magazine..td..Weapon.Reload.." s"
   result = result..td..getValue(Weapon, "Mastery", true, true)
   if(getValue(Weapon, "Type") ~= "Arch-Gun") then
       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 BuildGunComparisonTable(Weapons)

   local styleString = "border: 1px solid black;border-collapse: collapse;"--"background-color:transparent;color:black;border: 1px solid black;border-collapse: collapse;"
   local tHeader = ""
   tHeader = tHeader..'\n{| cellpadding="1" cellspacing="0" class="listtable sortable" style="font-size:11px;"'--margin:auto;text-align:center;border:1px solid black;font-size:11px;"'
   tHeader = tHeader..'\n! style="'..styleString..'"|Name'
   tHeader = tHeader..'\n! style="'..styleString..'"|Trigger Type'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Damage'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Critical Chance'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Critical Damage'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Status Chance'
   tHeader = tHeader..'\n! style="'..styleString..'"|Projectile Type'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Fire Rate'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Magazine Size'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Reload Time'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Mastery Rank'
   if (Shared.tableCount(Weapons) > 1) and getValue(Weapons[1], "Type") ~= "Arch-Gun" then
       tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Disposition'
   end
   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|}"

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..linkMeleeClass(Weapon.Class)
   end
   result = result..'||data-sort-value="'..GetDamage(getAttack(Weapon, "Normal"))..'" style="'..styleString..'"|'..GetDamageString(getAttack(Weapon, "Normal"))
   result = result..td..Weapon.SlideAttack
   result = result..td..Shared.round(getValue(Weapon, "FireRate", true), 3, 2)..td..getValue(Weapon, "CritChance", true, true)..td..getValue(Weapon, "CritMultiplier", true, true)
   result = result..td..getValue(Weapon, "StatusChance", true, true)
   result = result..td..getValue(Weapon, "Mastery", true, true)
   if(getValue(Weapon, "Type") ~= "Arch-Melee") then
       result = result..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
   end
   return result

end

local function BuildMeleeComparisonTable(Weapons, addClass)

   if(addClass == nil) then addClass = false end
   local styleString = "border: 1px solid black;border-collapse: collapse;"--"background-color:transparent;color:black;border: 1px solid black;border-collapse: collapse;"
   local tHeader = ""
   tHeader = tHeader..'\n{| cellpadding="1" cellspacing="0" class="listtable sortable" style="font-size:11px;"'--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'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Slide'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Attack Speed'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Critical Chance'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Critical Damage'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Status Chance'
   tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Mastery Rank'
   if (Shared.tableCount(Weapons) > 1) and getValue(Weapons[1], "Type") == "Melee" then
       tHeader = tHeader..'\n! style="'..styleString..'"|Stance'
       tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|Disposition'
   end
   
   local tRows = ""
   for i, Weap in pairs(Weapons) do
       tRows = tRows..BuildMeleeComparisonRow(Weap, addClass)
   end
   
   return tHeader..tRows.."\n|}"

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 = '
'
       result = result..'\n{| style="width:100%;"'
       result = result..'\n|-'
       result = result..'\n| class="left" | '
           result = result..""..Label..""
       result = result..''
       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
'
   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 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" |150px'
       nameRow = nameRow..'\n| style="vertical-align: text-top;" |'..Stance.Name..''
       if(Stance.PvP ~= nil and Stance.PvP) then
           nameRow = nameRow..'
(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" |150px'
       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.getWeaponCount(frame)

   local Type = frame.args ~= nil and frame.args[1] or frame
   local getFullList = frame.args ~= nil and frame.args[2]
   local count = 0
   local fullList = ""
   for i, val in Shared.skpairs(WeaponData["Weapons"]) do
       if(not Shared.contains(WeaponData["IgnoreInCount"], i)) then
           if(Type == nil or Type == "") then
               count = count + 1
               if(getFullList ~= nil) then fullList = fullList..'\n# '..val.Name end
           elseif(Type == "Warframe") then
               if(val.Type == "Primary" or val.Type == "Secondary" or val.Type == "Melee") then
                   count = count + 1
                   if(getFullList ~= nil) then fullList = fullList..'\n# '..val.Name end
               end
           elseif(Type == "Archwing") then
               if(val.Type == "Arch-Gun" or val.Type == "Arch-Melee") then
                   count = count + 1
                   if(getFullList ~= nil) then fullList = fullList..'\n# '..val.Name end
               end
           else
               if(val.Type == Type) then
                   count = count + 1
                   if(getFullList ~= nil) then fullList = fullList..'\n# '..val.Name end
               end
           end
       end
   end
   if(getFullList ~= nil) then return fullList end
   return count

end

--Gets melee weapon comparison --If an argument is specified, gets only for a specific class 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 getSecondaryCategory(weapon)

   local class = getValue(weapon, "Class", true)
   if(class == "Thrown") then
       return "Thrown"
   elseif(class == "Dual Shotguns" or class == "Shotgun Sidearm") then
       return "Shotgun"
   else
       local trigger = getValue(weapon, "Trigger", true)
       if(trigger == "Semi-Auto" or trigger == "Burst") then
           return "Semi-Auto"
       elseif(trigger == "Auto" or trigger == "Auto-Spool") then
           return "Auto"
       end
   end
   return "Other"

end

--Gets ALL Secondaries to compare function p.getSecondaryComparisonTable(frame)

   local Type = frame.args ~= nil and frame.args[1] or nil
   local WeapArray = p.getWeapons(function(x) 
                               local result = false
                               if(getValue(x, "Type", true) == "Secondary") then
                                   if(Type ~= nil) then
                                       return getSecondaryCategory(x) == Type
                                   else
                                       return true
                                   end
                               end
                                   return result
                               end)
   return BuildGunComparisonTable(WeapArray)

end

function getPrimaryCategory(weapon)

   local class = getValue(weapon, "Class", true)
   if(class == "Shotgun") then
       return "Shotgun"
   elseif(class == "Bow") then
       return "Bow"
   elseif(class == "Sniper Rifle") then
       return "Sniper"
   elseif(class == "Rifle") then
       local trigger = getValue(weapon, "Trigger", true)
       if(trigger == "Semi-Auto" or trigger == "Burst") then
           return "Semi-Auto"
       elseif(trigger == "Auto" or trigger == "Auto-Spool") then
           return "Auto"
       end
   end
   return "Other"

end

--Gets ALL Primaries to compare function p.getPrimaryComparisonTable(frame)

   local Type = frame.args ~= nil and frame.args[1] or nil
   local WeapArray = p.getWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Primary") then
                                   if(Type ~= nil) then
                                       return getPrimaryCategory(x) == Type
                                   else
                                       return true
                                   end
                               end
                                   return false
                               end)
   return BuildGunComparisonTable(WeapArray)

end

function p.getSentinelWeaponComparison(frame)

   local WeapArray = p.getWeapons(function(x) 
                                   return getValue(x, "Type", true) == "Sentinel"
                               end)
   return BuildGunComparisonTable(WeapArray)

end

function p.getArchGunComparison(frame)

   local WeapArray = p.getWeapons(function(x) 
                                   return getValue(x, "Type", true) == "Arch-Gun"
                               end)
   return BuildGunComparisonTable(WeapArray)

end

function p.getArchMeleeComparison(frame)

   local WeapArray = p.getWeapons(function(x) 
                                   return getValue(x, "Type", true) == "Arch-Melee"
                               end)
   return BuildMeleeComparisonTable(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 = p.getWeapons(function(x) return p.isMelee(x) and Shared.tableCount(getValue(x, "Polarities", true)) > 0 end)
   local Pistols = p.getWeapons(function(x) return x.Type == "Secondary" and  Shared.tableCount(getValue(x, "Polarities", true)) > 0 end)
   local Primaries = p.getWeapons(function(x) return (x.Type == "Primary") and Shared.tableCount(getValue(x, "Polarities", true)) > 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.."]]||"..p.GetPolarityString(Primaries[i])
       else
           tRows = tRows.."\n| ||"
       end
       if(i <= BCount) then
           tRows = tRows.."\n|[["..Pistols[i].Name.."]]||"..p.GetPolarityString(Pistols[i])
       else
           tRows = tRows.."\n| ||"
       end
       if(i <= ACount) then
           tRows = tRows.."\n|[["..Melees[i].Name.."]]||"..p.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
       local didWork, rowStr = pcall(Shared.round, Val1, Digits)
       if(didWork) then
           V1Str = rowStr
           local didWork, rowStr = pcall(Shared.round, Val2, Digits)
           if(didWork) then
               V2Str = rowStr
           else
               mw.log("Failed to round "..Val2)
           end
       else
           mw.log("Failed to round "..Val1)
       end
   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") and hasAttack(Weapon2, "Normal")) then
       local Att1 = getAttack(Weapon1, "Normal")
       local Att2 = getAttack(Weapon2, "Normal")
       local dmgString = ""
       dmgString = dmgString..buildCompareString(GetDamage(Att1), GetDamage(Att2), "base damage", {2, 1})
       dmgString = dmgString..buildCompareString(Att1.Damage["Impact"], Att2.Damage["Impact"], Icon._Proc("Impact", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
       dmgString = dmgString..buildCompareString(Att1.Damage["Puncture"], Att2.Damage["Puncture"], Icon._Proc("Puncture", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
       dmgString = dmgString..buildCompareString(Att1.Damage["Slash"], Att2.Damage["Slash"], Icon._Proc("Slash", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
       if(string.len(dmgString) > 0 and GetDamage(Att1) == GetDamage(Att2)) then
           dmgString = "\n**Equal base damage, but different composition:"..dmgString    
       end
       result = result..dmgString
   end
   if(hasAttack(Weapon1, "Charge")and hasAttack(Weapon2, "Charge")) then
       result = result..buildCompareString(GetDamage(Weapon1.ChargeAttack), GetDamage(Weapon2.ChargeAttack), "charge attack damage", {2, 1})
       result = result..buildCompareString(getValue(Weapon1, {"Charge", "ChargeTime"}), getValue(Weapon2, {"Charge", "ChargeTime"}), "charge time", {2, 1}, " s", {"Slower", "Faster"})
   end
   if(hasAttack(Weapon1, "Area") and hasAttack(Weapon2, "Area")) then
       result = result..buildCompareString(GetDamage(Weapon1.AreaAttack), GetDamage(Weapon2.AreaAttack), "area attack damage", {2, 1})
   end
   if(hasAttack(Weapon1, "Secondary") and hasAttack(Weapon2, "Secondary")) then
       result = result..buildCompareString(GetDamage(Weapon1.SecondaryAttack), GetDamage(Weapon2.SecondaryAttack), "secondary attack damage", {2, 1})
   end
   
   if(hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Normal") ) then
       local Att1 = getAttack(Weapon1, "Normal")
       local Att2 = getAttack(Weapon2, "Normal")
       if(Att1.CritChance ~= nil and Att2.CritChance ~= nil) then
           result = result..buildCompareString((Att1.CritChance * 100), (Att2.CritChance * 100), "critical chance", 2, "%")
       end
       result = result..buildCompareString(Att1.CritMultiplier, Att2.CritMultiplier, "critical damage multiplier", 2, "x")
       if(Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then
           result = result..buildCompareString((Att1.StatusChance * 100), (Att2.StatusChance * 100), "status chance", 2, "%")
       end
       result = result..buildCompareString(Att1.FireRate, Att2.FireRate, "fire rate", 2, " round<s>/sec")
       
       --Handling Damage Falloff        
       if(Att1.Falloff ~= nil and Att2.Falloff == nil) then
           result = result.."\n** "..Att1.Falloff.StartRange.."m - "..Att1.Falloff.EndRange.."m damage falloff"
           if(Att1.Falloff.Reduction ~= nil) then
              result = result.." with up to "..(Att1.Falloff.Reduction * 100).."% damage reduction"
           end
       elseif(Att2.Falloff ~= nil and Att1.Falloff == nil) then
           result = result.."\n** No "..Att2.Falloff.StartRange.."m - "..Att2.Falloff.EndRange.."m damage falloff"
           if(Att2.Falloff.Reduction ~= nil) then
               result = result.." with up to "..(Att2.Falloff.Reduction * 100).."% damage reduction"
           end
       elseif(Att1.Falloff ~= nil and Att2.Falloff ~= nil) then
           result = result..buildCompareString(Att1.Falloff.StartRange, Att2.Falloff.StartRange, "range before damage falloff starts", 2, "m", {"Longer", "Shorter"})
           result = result..buildCompareString(Att1.Falloff.EndRange, Att2.Falloff.EndRange, "range before damage falloff ends", 2, "m", {"Longer", "Shorter"})
           if(Att1.Falloff.Reduction ~= nil and Att2.Falloff.Reduction ~= nil) then
               result = result..buildCompareString(Att1.Falloff.Reduction * 100, Att2.Falloff.Reduction * 100, "max damage reduction due to falloff", 2, "%", {"Larger", "Smaller"})
           end
       end
   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"})
   local Acc1 = getValue(Weapon1, "Accuracy")
   local Acc2 = getValue(Weapon2, "Accuracy")
   if(type(Acc1) == "number" and type(Acc2) == "number") then
       result = result..buildCompareString(Acc1, Acc2, "accurate", 0, nil, {"More", "Less"})
   end
       
   --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 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 ("..p.GetPolarityString(Weapon1).." vs. "..p.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 = ""
   local Att1 = getAttack(Weapon1, "Normal")
   local Att2 = getAttack(Weapon2, "Normal")
   dmgString = dmgString..buildCompareString(GetDamage(Att1), GetDamage(Att2), "base damage", {2, 1})
   dmgString = dmgString..buildCompareString(Att1.Damage["Impact"], Att2.Damage["Impact"], Icon._Proc("Impact", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
   dmgString = dmgString..buildCompareString(Att1.Damage["Puncture"], Att2.Damage["Puncture"], Icon._Proc("Puncture", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
   dmgString = dmgString..buildCompareString(Att1.Damage["Slash"], Att2.Damage["Slash"], Icon._Proc("Slash", "text").." damage", {2, 1}, nil, {"Higher", "Lower"}, "\n***")
   if(string.len(dmgString) > 0 and GetDamage(Att1) == GetDamage(Att2)) then
       dmgString = "\n**Equal base damage, but different composition:"..dmgString    
   end
   result = result..dmgString
   
   
   if(Att1.CritChance ~= nil and Att2.CritChance ~= nil) then
       result = result..buildCompareString((Att1.CritChance * 100), (Att2.CritChance * 100), "critical chance", 2, "%")
   end
   result = result..buildCompareString(Att1.CritMultiplier, Att2.CritMultiplier, "critical damage multiplier", {2, 1}, "x")
   
   if(Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then
       result = result..buildCompareString((Att1.StatusChance * 100), (Att2.StatusChance * 100), "status chance", 2, "%")
   end
   result = result..buildCompareString(Att1.FireRate, Att2.FireRate, "attack speed", 2)
   result = result..buildCompareString(Icon._Pol(Weapon1.StancePolarity), Icon._Pol(Weapon2.StancePolarity), "Stance Polarity", nil, nil, {"Different", "Different"})
   result = result..buildCompareString(getValue(Weapon1, "ChannelMult", true), getValue(Weapon2, "ChannelMult", true), "Channeling Multiplier", 1, "x")
   
   --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 ("..p.GetPolarityString(Weapon1).." vs. "..p.GetPolarityString(Weapon2)..")"
   end
   
   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 'ERROR: Must compare two weapons'
   end
   
   local Weapon1 = p.getWeapon(WeapName1)
   if(Weapon1 == nil) then
       return 'ERROR: Could not find '..WeapName1..''
   end
   local Weapon2 = p.getWeapon(WeapName2)
   if(Weapon2 == nil) then
       return 'ERROR: Could not find '..WeapName2..''
   end
   
   if(p.isMelee(Weapon1)) then
       return buildMeleeComparisonString(Weapon1, Weapon2)..""
   else
       return buildGunComparisonString(Weapon1, Weapon2)..""
   end

end

function p.buildConclaveComparison(frame)

   local WeapName1 = frame.args[1]
   local WeapName2 = frame.args[2]
   
   if(WeapName1 == nil or WeapName2 == nil) then
       return 'ERROR: Must compare two weapons'
   end
   
   local Weapon1 = p.getConclaveWeapon(WeapName1)
   if(Weapon1 == nil) then
       return 'ERROR: Could not find '..WeapName1..''
   end
   local Weapon2 = p.getConclaveWeapon(WeapName2)
   if(Weapon2 == nil) then
       return 'ERROR: Could not find '..WeapName2..''
   end
   
   if(p.isMelee(Weapon1)) then
       return buildMeleeComparisonString(Weapon1, Weapon2)..""
   else
       return buildGunComparisonString(Weapon1, Weapon2)..""
   end

end

function p.buildFamilyComparison(frame)

   local WeapName = frame.args ~= nil and frame.args[1] or frame
   if(WeapName == nil) then
       return 'ERROR: Must provide a Weapon name'
   end
   
   local Weapon = p.getWeapon(WeapName)
   if(Weapon == nil) then
       return 'ERROR: Could not find '..WeapName1..''
   end
   if(Weapon.Family == nil) then
       return 'ERROR: '..WeapName..' doesn\'t have a family'
   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 = ""
   if(Weapon == nil) then
       return ""
   elseif(Weapon.IgnoreCategories ~= nil and Weapon.IgnoreCategories) then
       return ""
   end
   if(Weapon.Type ~= nil) then
       if(Weapon.Type == "Arch-Melee") then
           result = result..""
       elseif(Weapon.Type == "Arch-Gun") then
           result = result..""
       else
           result= result..""
       end
   end
   if(Weapon.Class ~= nil) then
       if(Weapon.Class == "Rifle") then
           result = result..""
       else
           result = result..""
       end
   end
   
   local augments = getAugments(Weapon)
   if(Shared.tableCount(augments) > 0) then
       result = result..""
   end
   
   if(HasTrait(Weapon, "Prime")) then
       result = result..""
       if(HasTrait(Weapon, "Never Vaulted")) then
           result = result..""
       elseif(HasTrait(Weapon, "Vaulted")) then
           result = result..""
       end
   end
   if(HasTrait(Weapon, "Grineer")) then
       result = result..""
   elseif(HasTrait(Weapon, "Corpus")) then
       result = result..""
   elseif(HasTrait(Weapon, "Infested")) then
       result = result..""
   elseif(HasTrait(Weapon, "Tenno")) then
       result = result..""
   end
   local attack = nil
   if(hasAttack(Weapon, "Normal")) then
       attack = getAttack(Weapon, "Normal")
   elseif(hasAttack(Weapon, "Charge")) then
       attack = getAttack(Weapon, "Charge")
   end
   if(attack ~= nil) then
       local bestPercent, bestElement = GetDamageBias(attack)
       if(bestElement == "Impact" or bestElement == "Puncture" or bestElement == "Slash") then
           if(bestPercent > .38) then
               result = result..""
           else
               result = result..""
           end
       end
       
       for key, value in Shared.skpairs(attack.Damage) do
           if(key ~= "Impact" and key ~= "Puncture" and key ~= "Slash") then
               result = result..""
           end
       end
   end
   
   if(hasAttack(Weapon, "Secondary")) then
       result = result..""
   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.."" --span class = displays the mod tooltip in the table on hover.
       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.."
" 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 = p.getWeapons(function(x) 
                                   local Dmg, Element 
                                   if (hasAttack(x, "Normal")) then
                                       Dmg, Element = GetDamageBias(getAttack(x, "Normal"), true)
                                   elseif(hasAttack(x, "Charge")) then
                                       Dmg, Element = GetDamageBias(getAttack(x, "Charge"), true)
                                   else
                                       return false
                                   end
                                   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.."|| "..getValue(Weapon, "Class", true, true)
       if(hasAttack(Weapon, "Normal")) then
           thisRow = thisRow.."||"..getValue(Weapon, {"Normal", DamageType}).."||"..getValue(Weapon, {"Normal", "DamageBias"}, true)
       elseif(hasAttack(Weapon, "Charge")) then
           thisRow = thisRow.."||"..getValue(Weapon, {"Charge", DamageType}).."||"..getValue(Weapon, {"Charge", "DamageBias"}, true)
       end
       
       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(Weapon.Mastery ~= nil) then
           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
   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==="
           local tempList = p.shortLinkList(TypeTable["Primary"])
           for i, text in pairs(tempList) do
               thisTable = thisTable.."\n* "..text
           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==="
           local tempList = p.shortLinkList(TypeTable["Secondary"])
           for i, text in pairs(tempList) do
               thisTable = thisTable.."\n* "..text
           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==="
           local tempList = p.shortLinkList(TypeTable["Melee"])
           for i, text in pairs(tempList) do
               thisTable = thisTable.."\n* "..text
           end
       end
       thisTable = thisTable.."\n|}"
       result = result..thisTable
   end
   return result

end

function p.getMasteryShortList(frame)

   local WeaponType = frame.args[1]
   local MasteryRank = tonumber(frame.args[2])
       
   local weapArray = p.getWeapons(function(x) 
                                   if(x.Type ~= nil and x.Mastery ~= nil) then
                                       return x.Type == WeaponType and x.Mastery == MasteryRank
                                   else
                                       return false
                                   end
                               end)
   
   local result = ""
   local shortList = p.shortLinkList(weapArray)
   for i, pair in Shared.skpairs(shortList) do
       if(string.len(result) > 0) then result = result.." • " end
       result = result..pair
   end
   return result

end

function p.getRivenDispositionList(frame)

   local WeaponType = frame.args[1]
   local Disposition = tonumber(frame.args[2])
       
   local weapArray = p.getWeapons(function(x) 
                                   if(x.Type ~= nil and x.Disposition ~= nil) then
                                       return (string.upper(WeaponType) == "ALL" or x.Type == WeaponType) and x.Disposition == Disposition
                                   else
                                       return false
                                   end
                               end)
   
   local result = ""
   local shortList = p.shortLinkList(weapArray)
   for i, pair in Shared.skpairs(shortList) do
       result = result..'\n* '..pair
   end
   return result

end

function p.getRivenDispositionTable(frame)

   local WeaponType = frame.args[1]
       
   local result = '{| class="article-table" border="0" cellpadding="1" cellspacing="1" style="width: 100%"'
   result = result..'\n|-'
   for i = 5, 1, -1 do
       result = result..'\n! scope="col" style="text-align:center;"|'..Icon._Dis(i)
   end
   result = result..'\n|-'
   for i = 5, 1, -1 do
       result = result..'\n| style="vertical-align:top" |'
       result = result..p.getRivenDispositionList({args = {WeaponType, i}})
   end
   result = result..'\n|}'
   
   return result

end

function p.getConclaveList(frame)

   local WeaponType = frame.args[1]
       
   local weapArray = p.getWeapons(function(x) 
                                   if(x.Type ~= nil and x.Conclave ~= nil) then
                                       return x.Type == WeaponType and x.Conclave
                                   else
                                       return false
                                   end
                               end)
   
   local result = ""
   local shortList = p.shortLinkList(weapArray)
   for i, pair in Shared.skpairs(shortList) do
       result = result..'\n* '..pair
   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.getMeleeComparisonTable({})..p.getSecondaryComparisonTable({})

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 and p.isArchwing(weapon) == 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 and p.isArchwing(weapon) == nil) then
           result = result.."\n"..key.." does not have a Class"
       end
       if(weapon.NormalAttack ~= nil and weapon.NormalAttack.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


function p.buildTunaWeaponTable(frame)

   local Category = frame.args ~= nil and frame.args[1] or frame
   local Weapons = p.getWeapons( function(x)
                                   return getValue(x, "Type", true) == Category
                               end)
                                   
   
   local result = '{| style="margin:auto;text-align:center;"'
   local i = 0
   for key, Weapon in Shared.skpairs(Weapons) do
       i = i + 1
       local theImage = Weapon.Image ~= nil and Weapon.Image or "Panel.png"
       if((i - 1) % 7 == 0) then 
           result = result..'\n|-'
       end
       result = result..'\n| style="width:85px" |70px'
   end
   result = result..'\n|}'
   return result

end

-- and we are back... new table building functions !

local function BuildCompRow(Head,Weapon)

   local styleString = ""--"border: 1px solid lightgray;"
   local td = 
   local result = 
   local ValNameZ = nil
   local ValName = nil
   
   local attName = ""
   if(hasAttack(Weapon, "Charge")) then
       attName = "Charge"
   elseif(hasAttack(Weapon, "Normal")) then
       attName = "Normal"
   else
       return ""
   end
 mw.log(Weapon.Name)
 mw.log(attName)

result = '\n|-\n|'

   for i, Hline in ipairs(Head) do
       ValNameZ = nil
       ValNameZ = Hline[1]
       mw.log(ValNameZ,ValNameZ[1],ValNameZ[2])
       if(type(ValNameZ) == "table" and ValNameZ[1]=="default") then
           ValName={attName,ValNameZ[2]}
       elseif(type(ValNameZ) == "table") then ValName={ValNameZ[1],ValNameZ[2]}
       else ValName=ValNameZ
       end
       mw.log(ValName,ValName[1],ValName[2])
           
       if(i == 1) then td =  else td='||' end
       mw.log(getValue(Weapon, ValName))
       if(getValue(Weapon, ValName)~=nil) then
           if(Hline[2]) then 
           result = result..td..'data-sort-value="'..getValue(Weapon, ValName)..'" style="'..styleString..'"|'..getValue(Weapon, ValName,true,true,true)
           else
           result = result..td..'style="'..styleString..'"|'..getValue(Weapon, ValName,true,true,true)    
           end
       else result = result..td..'style = "'..styleString..'"|'.."N/A" end
   end


   return result

end

local function BuildCompTable(Head,Weapons)

   local styleString = "border: 1px solid black;border-collapse: collapse;"
   local tHeader = ""
   tHeader = tHeader..'\n{| cellpadding="1" cellspacing="0" class="listtable sortable" style="font-size:11px;"'

for i, Hline in ipairs(Head) do if(Hline[2] == true) then tHeader = tHeader..'\n! data-sort-type="number" style="'..styleString..'"|'..Hline[3].. else tHeader = tHeader..'\n! style="'..styleString..'"|'..Hline[3].. end end -- mw.log(tHeader)


   local tRows = ""
   for i, Weap in pairs(Weapons) do
       rowStr = BuildCompRow(Head, Weap)
       tRows = tRows..rowStr
   end

-- mw.log(tRows)

   return  tHeader..tRows.."\n|}"

end

function p.getCompTableGuns(frame)

   local Catt = frame.args ~= nil and frame.args[1]
   local Type = frame.args ~= nil and frame.args[2] or nil
       if(Type == "All") then Type = nil end
   local WeapArray = {}
   if(Catt == "Primary") then WeapArray = p.getWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Primary") then
                                   if(Type ~= nil) then return getPrimaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)
   elseif(Catt == "Secondary") then WeapArray = p.getWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Secondary") then
                                   if(Type ~= nil) then return getSecondaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)

elseif(Catt == "Sentinel") then WeapArray = p.getWeapons(function(x)

                                   return getValue(x, "Type", true) == "Sentinel"
                                   end)
   else return "\n Error : Wrong Class (use Primary, Secondary, or Sentinel)"
   end
   

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Trigger",false,"Trigger Type"}) table.insert(Head,{{"default","Damage"},true,"Damage"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{{"default","BulletType"},false,"Projectile Type"}) table.insert(Head,{"FireRate",true,"Fire Rate"}) table.insert(Head,{"Magazine",true,"Magazine Size"}) table.insert(Head,{"Reload",true,"Reload Time"}) table.insert(Head,{"Mastery",true,"Mastery Rank"}) table.insert(Head,{"Disposition",true,"Disposition"})

   return BuildCompTable(Head,WeapArray)

end

function p.getCompTableConclaveGuns(frame)

   local Catt = frame.args ~= nil and frame.args[1]
   local Type = frame.args ~= nil and frame.args[2] or nil
       if(Type == "All") then Type = nil end
   local WeapArray = {}
   if(Catt == "Primary") then WeapArray = p.getConclaveWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Primary") then
                                   if(Type ~= nil) then return getPrimaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)
   elseif(Catt == "Secondary") then WeapArray = p.getConclaveWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Secondary") then
                                   if(Type ~= nil) then return getSecondaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)
   else return "\n Error : Wrong Class (use Primary or Secondary)"
   end
   

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Trigger",false,"Trigger Type"}) table.insert(Head,{{"default","Damage"},true,"Damage"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{{"default","BulletType"},false,"Projectile Type"}) table.insert(Head,{"FireRate",true,"Fire Rate"}) table.insert(Head,{"Magazine",true,"Magazine Size"}) table.insert(Head,{"Reload",true,"Reload Time"}) table.insert(Head,{"Mastery",true,"Mastery Rank"}) table.insert(Head,{"Disposition",true,"Disposition"})

   return BuildCompTable(Head,WeapArray)

end

function p.getCompTableArchGuns(frame)

   local WeapArray = {}
   WeapArray = p.getWeapons(function(x) 
                                   return getValue(x, "Type", true) == "Arch-Gun"
                                   end)
   

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Trigger",false,"Trigger Type"}) table.insert(Head,{{"default","Damage"},true,"Damage"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{{"default","BulletType"},false,"Projectile Type"}) table.insert(Head,{"FireRate",true,"Fire Rate"}) table.insert(Head,{"Magazine",true,"Magazine Size"}) table.insert(Head,{"Reload",true,"Reload Time"}) table.insert(Head,{"Mastery",true,"Mastery Rank"})

   return BuildCompTable(Head,WeapArray)

end


function p.getCompTableMelees(frame)

   --Changed formatting, now only takes type since only class handled is Melee
   --Keeping old formatting to avoid breaking pages
   local Type = frame.args ~= nil and frame.args[2] or nil
   if(Type == nil) then Type = frame.args ~= nil and frame.args[1] or nil end 
   if(Type == "All") then Type = nil end
   local WeapArray = {}
   WeapArray = getMeleeWeapons(Type)
   local addClass = Type == nil or Shared.contains(Type, ",")

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Class",false,"Type"}) table.insert(Head,{{"Normal","Damage"},true,"Normal"}) table.insert(Head,{"SlideAttack",true,"Slide"}) table.insert(Head,{{"default","FireRate"},true,"Attack Speed"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{"Mastery",true,"Mastery Rank"}) table.insert(Head,{"STANCEPOLARITY",false,"Stance"}) table.insert(Head,{"Disposition",true,"Disposition"}) for k, v in pairs(Head[1]) do mw.log(k, v) end

   return BuildCompTable(Head,WeapArray)

end

--As above, but for conclave function p.getCompTableConclaveMelees(frame)

   local Type = frame.args ~= nil and frame.args[1] or nil
   if(Type == "All") then Type = nil end
   local WeapArray = {}
   WeapArray = getConclaveMeleeWeapons(Type)
   local addClass = Type == nil or Shared.contains(Type, ",")

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Class",false,"Type"}) table.insert(Head,{{"Normal","Damage"},true,"Normal"}) table.insert(Head,{"SlideAttack",true,"Slide"}) table.insert(Head,{{"default","FireRate"},true,"Attack Speed"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{"Mastery",true,"Mastery Rank"}) table.insert(Head,{"STANCEPOLARITY",false,"Stance"}) table.insert(Head,{"Disposition",true,"Disposition"}) for k, v in pairs(Head[1]) do mw.log(k, v) end

   return BuildCompTable(Head,WeapArray)

end

function p.getCompTableArchMelees(frame)

   local WeapArray = {}
   WeapArray = p.getWeapons(function(x) 
                                   return getValue(x, "Type", true) == "Arch-Melee"
                               end)

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{{"Normal","Damage"},true,"Normal"}) table.insert(Head,{"SlideAttack",true,"Slide"}) table.insert(Head,{{"default","FireRate"},true,"Attack Speed"}) table.insert(Head,{"CritChance",true,"Critical Chance"}) table.insert(Head,{"CritMultiplier",true,"Critical Damage"}) table.insert(Head,{"StatusChance",true,"Status Chance"}) table.insert(Head,{"Mastery",true,"Mastery Rank"}) for k, v in pairs(Head[1]) do mw.log(k, v) end

   return BuildCompTable(Head,WeapArray)

end

function p.getCompTableSpeedGuns(frame)

   local Catt = frame.args ~= nil and frame.args[1]
   local Type = frame.args ~= nil and frame.args[2] or nil
       if(Type == "All") then Type = nil end
   local WeapArray = {}
   if(Catt == "Primary") then WeapArray = p.getWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Primary") then
                                   if(Type ~= nil) then return getPrimaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)
   elseif(Catt == "Secondary") then WeapArray = p.getWeapons(function(x) 
                               if(getValue(x, "Type", true) == "Secondary") then
                                   if(Type ~= nil) then return getSecondaryCategory(x) == Type else return true end
                               end
                                   return false
                               end)

elseif(Catt == "Sentinel") then WeapArray = p.getWeapons(function(x)

                                   return getValue(x, "Type", true) == "Sentinel"
                                   end)

elseif(Catt == "Arch-Gun") then WeapArray = p.getWeapons(function(x)

                                   return getValue(x, "Type", true) == "Arch-Gun"
                                   end)
   else return "\n Error : Wrong Class (use Primary, Secondary, Sentinel, or Arch-Gun)"
   end
   -- special sorting for projectile weapons
   local WeapArray2 = {}
   for k, Weapon in ipairs(WeapArray) do
       local attName = ""
       if(hasAttack(Weapon, "Charge")) then
           attName = "Charge"
       elseif(hasAttack(Weapon, "Normal")) then
           attName = "Normal"
       else
           return ""
       end
       if(getValue(Weapon,{attName, "BulletType"}, false) == "Projectile") then
           table.insert(WeapArray2, Weapon)
       elseif(getValue(Weapon,{"Area", "BulletType"}, false) == "Projectile") then
           table.insert(WeapArray2, Weapon)
       elseif(getValue(Weapon,{"Secondary", "BulletType"}, false) == "Projectile") then
           table.insert(WeapArray2, Weapon)
       elseif (getValue(Weapon,{attName, "BulletType"}, false) == "Thrown") then
           table.insert(WeapArray2, Weapon)
       end
   end

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{"Class",false,"Type"}) table.insert(Head,{{"Normal","PROJECTILESPEED"},true,"Flight Speed"}) table.insert(Head,{{"Charge","PROJECTILESPEED"},true,"Charge Flight Speed"}) table.insert(Head,{"SPECIALFSPEED",true,"Alt-Fire / Special"})

   return BuildCompTable(Head,WeapArray2)

end

function p.getCompTableSpeedMelees(frame)

   local Catt = frame.args ~= nil and frame.args[1]
   local Type = frame.args ~= nil and frame.args[2] or nil
   if(Type == "All") then Type = nil end
   local WeapArray = {}
   if(Catt == "Melee") then WeapArray = getMeleeWeapons(Type)

local addClass = Type == nil or Shared.contains(Type, ",") elseif(Catt == "Arch-Melee") then WeapArray = p.getWeapons(function(x)

                                   return getValue(x, "Type", true) == "Arch-Melee"
                               end)
   else return "\n Error : Wrong Class (use Melee or Arch-Melee)"
   end
   -- special sorting for projectile weapons ONLY WORKS FOR GLAIVE TYPE MELEE WEAPONS !!!
   local WeapArray2 = {}
   for k, Weapon in ipairs(WeapArray) do
       if (getValue(Weapon,{"Normal", "BulletType"}, false) == "Thrown") then
           table.insert(WeapArray2, Weapon)
       end
   end

local Head=Template:"Name",false,"Name" -- better if Name is always the first column !!! table.insert(Head,{{"Normal","PROJECTILESPEED"},true,"Flight Speed"}) table.insert(Head,{"SPECIALFSPEED",true,"Special"})

   return BuildCompTable(Head,WeapArray2)

end

function p.weaponTooltip(frame)

   local weapName = frame.args ~= nil and frame.args[1]
   --there's no "Dark Split-Sword" in m:weapons/data -> setting name to dual sword variant
   if weapName == 'Dark Split-Sword' then
       weapName = 'Dark Split-Sword (Dual Swords)'
   end
   local Title = frame.args[2]
   
   local A2Name = nil
   local A2Value = nil
   local C1Name = nil
   local C1Value = nil
   local C1Toggle = nil
   local C2Name = nil
   local C2Value = nil
   local titleText = 
   local hasCharged = false
   local attackType = 'Normal'
   local IPSCounter = 0
   local attack = nil
   local attackText = 
   local space = ' '
   local attackBiasText = 
   
   if weapName == nil then
       return nil
   end
   local Weapon = p.getWeapon(weapName)
   if Weapon == nil then
       return 'No weapon '..weapName..' found.'
   end
   
   --for weapons which have no max ammo
   local weaponType = Weapon.Type
   local typeExceptions = {"Sentinel","Emplacement","Arch-Gun","Gear"}
   --mw.log(weaponType)
   
   local function Value(valueName, asString, forTable)
       if(asString == nil) then asString = false end
       if(forTable == nil) then forTable = false end
       return getValue(Weapon, valueName, true, asString, forTable)
   end
   local isMelee = p.isMelee(Weapon) == "yes"
   
   --mw.log(isMelee)
   
   local chargedExceptions = {"Tiberon Prime", "Kohm", "Kohmak", "Twin Kohmak", "Stug"} -- weapons which have a charged attack but normal attack values are used for the tooltip
   local secondaryExceptions = {"Penta", "Carmine Penta", "Secura Penta"}
   local areaExceptions = {"Ogris", "Zarr", "Tonkor", "Kulstar", "Angstrum", "Prisma Angstrum"}
   local secondaryAreaExceptions ={"Lenz"}
   
   if isMelee ~= true then
       if Shared.contains(chargedExceptions, weapName) ~= true and Value({"Charge","AttackName"}) ~= nil then
           hasCharged = true
           attackType = 'Charge'
       end
       if Shared.contains(secondaryExceptions, weapName) then
           attackType = 'Secondary'
       elseif Shared.contains(areaExceptions, weapName) then
           attackType = 'Area'
       elseif Shared.contains(secondaryAreaExceptions, weapName) then
           attackType = 'SecondaryArea'
       end
   end
   --mw.log(hasCharged)
   --mw.log(attackType)
   
   attack = getAttack(Weapon, attackType)
   local count = 0
   for type, dmg in Shared.skpairs(attack.Damage) do
       if count == 0 then
           attackText = '\n| style=\"padding-right:2px;\" |'..Icon._Proc(type,,'white')..space..dmg
           count = count + 1
       else
           attackText = attackText..'|| style=\"padding-right:4px;\" |'..Icon._Proc(type,,'white')..space..dmg
       end
   end
   if(hasMultipleTypes(attack)) then
       attackBiasText = '\n| colspan=4 |'..GetDamageString(attack, nil).." ("..GetDamageBiasString(attack,nil,,nil,'white')..")"
   end
   if isMelee == true then
       A2Name = 'Type'
       A2Value = 'Class'
       C1Name = 'Atk. Speed'
       C1Value = 'FireRate'
       C1Toggle = true
       C2Name = 'Block Resist.'
       C2Value = 'BlockResist'
   else
       A2Name = 'Trigger'
       A2Value = 'Trigger'
       C2Name = 'Noise'
       C2Value = 'NoiseLevel'
       if hasCharged == true then
           C1Name = 'Charge Time'
           if weapName == "Staticor" then
               C1Value = {'Area','ChargeTime'}
           else
               C1Value = {'Charge','ChargeTime'}
           end
           C1Toggle = true
       else
           C1Name = 'Fire Rate'
           C1Value = 'FireRate'
       end
   end
       
   local function Link(linkName)
       local spanStart = ''
       local spanEnd = ''
       return spanStart..linkName..spanEnd
   end
   
   local zeroPadding = '\n| style=\"padding:0px;\" |'
   local newRow = '\n|-'
   local spacer = '\n| class=\"Spacer\" |'
   local halfTable = '\n| class=\"TableHalf\" |'
   local dataText = '\n{| class=\"Data\" style=\"font-size:12px;\"'
   local dataTextCenter = '\n{| class=\"Data\" style=\"font-size:12px; text-align:center;\"'
   local tableEnd = '\n|}'
   
   local image = '\n| class=\"Image\" style=\"height:120px;\" | 160px'
   
   if Title then
       titleText = newRow..'\n! class=\"Title\"|'..Value("Name")..newRow..spacer
   end
   
   --creating the table
   local result = '{| class=\"Sub\"'..newRow..image..newRow..spacer..newRow..zeroPadding
   result = result..dataText..newRow
   result = result..halfTable..Link("Slot")..space..Value("Type")..halfTable..Link(A2Name)..space..Value(A2Value)..tableEnd
   result = result..newRow..spacer..titleText..newRow..zeroPadding
   result = result..dataTextCenter..newRow..attackText
   if(attackBiasText ~= ) then
       result = result..newRow..attackBiasText
   end
   result = result..tableEnd
   result = result..newRow..spacer..newRow..zeroPadding..dataText..newRow..halfTable..Link("Crit")..space..Value("CritChance",true)..' | '..Value("CritMultiplier",true)..halfTable..Link("Status")..space..Value("StatusChance",true)
   result = result..newRow..halfTable..Link(C1Name)..space..Value(C1Value,C1Toggle)..halfTable..Link(C2Name)..space..Value(C2Value)
   --if not melee and not fishing spear => reload and ammo stats
   if not isMelee and weaponType ~= "Gear" then
       result = result..newRow..halfTable..Link("Reload")..space..Value("Reload", true, true)..halfTable..Link("Ammo")..space..Value("Magazine")
       --if has max ammo => add max ammo stat
       if not Shared.contains(typeExceptions, weaponType) then
           result = result..'/'..Value("MaxAmmo")
       end
   end
   result = result..tableEnd..tableEnd
   
   return result

end

return p

Community content is available under CC-BY-SA unless otherwise noted.