Aucun résumé des modifications |
Aucun résumé des modifications |
||
(182 versions intermédiaires par 4 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
+ | --- '''Weapons''' contient toutes les [[Armes]] de [[WARFRAME]]. |
||
+ | -- |
||
+ | -- @module weapons |
||
+ | -- @alias p |
||
+ | -- @attribution [[User:Cephalon Scientia|Cephalon Scientia]] |
||
+ | -- @attribution [[User:FINNER|FINNER]] |
||
+ | -- @attribution [[User:Falterfire|Falterfire]] |
||
+ | -- @attribution [[User:Gigamicro|Gigamicro]] |
||
+ | -- @attribution [[User:Flaicher|Flaicher]] |
||
+ | -- @attribution [[User:Synthtech|Synthtech]] |
||
+ | -- @attribution [[User:Yazuh|Yazu]] (retranscription) |
||
+ | -- @image IconPrimaryWeaponRifle.png |
||
+ | -- @require [[Module:StatObject]] |
||
+ | -- @require [[Module:DamageTypes]] |
||
+ | -- @require [[Module:Polarity]] |
||
+ | -- @require [[Module:Math]] |
||
+ | -- @require [[Module:Table]] |
||
+ | -- @require [[Module:Tooltips]] |
||
+ | -- @require [[Module:Version]] |
||
+ | -- @require [[Module:Stances/data]] |
||
+ | -- @require [[Module:Weapons/data]] |
||
+ | -- @require [[Module:Weapons/Conclave/data]] |
||
+ | -- @release stable |
||
+ | -- <nowiki> |
||
+ | |||
+ | -- TODO: Add LuaDoc style comments to new functions |
||
local p = {} |
local p = {} |
||
− | local |
+ | local Delay = require([[Module:Delay]]) |
− | local |
+ | local WeaponData = Delay.require([[Module:Weapons/data]]) |
− | local |
+ | local ConclaveData = Delay.require([[Module:Weapons/Conclave/data]]) |
− | local |
+ | local Tooltip = Delay.require([[Module:Tooltips]]) -- full, icon |
− | local |
+ | local Version = Delay.require([[Module:Version]]) -- _getVersion, _getVersionDate |
− | local |
+ | local Polarity = Delay.require([[Module:Polarity]]) -- _pols, _polarity |
+ | local Math = Delay.require([[Module:Math]]) -- formatnum |
||
+ | local Table = Delay.require([[Module:Table]]) -- size, skpairs |
||
+ | local iterationOrderArray = require([[Module:DamageTypes]]).iterationOrderArray |
||
+ | -- TODO: Should decouple from localized names for internationalization |
||
− | local Elements = { |
||
+ | local VARIANT_LIST = { |
||
− | "Impact", "Perforation", "Tranchant", "Feu", "Glace", "Poison", |
||
− | + | "Prime", "Prisma", "Wraith", "Vandal", "Vaykor", "Synoid", "Telos", "Secura", |
|
+ | "Sancti", "Rakta", "Mara", "Carmine", "Ceti", "Dex", "MK1", "Kuva", "Principe" |
||
− | "Viral" |
||
− | } |
||
− | local Physical = {"Impact", "Perforation", "Tranchant"} |
||
− | local UseDefaultList = { |
||
− | "NOISELEVEL", "AMMOTYPE", "MAXAMMO", "DISPOSITION", "CHANNELMULT", |
||
− | "HEADSHOTMULTIPLIER" |
||
− | } |
||
− | local VariantList = { |
||
− | "Prime", "Prisma", "Wraith", "Vandal", "Vaykor", "Synoid", "Telos", |
||
− | "Secura", "Sancti", "Rakta", "Mara", "MK1" |
||
} |
} |
||
+ | table.unpack = table.unpack or unpack |
||
− | -- ======================= |
||
− | -- ===== FILTERS ===== |
||
− | -- ======================= |
||
+ | local StatObject = require [[Module:StatObject]] |
||
− | local function weaponFilter_Melee(weap, mainCat, subCat) |
||
+ | p.__StatObject = StatObject |
||
− | return weap.Type == mainCat and weap.Class == subCat |
||
+ | local statRead = StatObject.statRead |
||
− | end |
||
+ | local statFormat = StatObject.statFormat |
||
+ | local indexes = StatObject.meta.indexes |
||
− | local function weaponFilter_NonMelee(weap, mainCat, subCat, triggerType) |
||
+ | local ors = StatObject.meta.ors |
||
− | if (triggerType ~= nil and triggerType == "Hybride") then |
||
+ | local unpacks = StatObject.meta.unpacks |
||
− | return |
||
− | weap.Type == mainCat and (subCat == nil or weap.Class == subCat) and |
||
− | Shared.contains(weap.Trigger, '/') |
||
− | else |
||
− | return |
||
− | weap.Type == mainCat and (subCat == nil or weap.Class == subCat) and |
||
− | (triggerType == nil or weap.Trigger == triggerType) |
||
− | end |
||
− | end |
||
+ | local passes = StatObject.meta.passes |
||
− | -- ======================= |
||
+ | local percent = StatObject.meta.percent |
||
− | -- ===== OTHERS ===== |
||
+ | local percents = StatObject.meta.percents |
||
− | -- ======================= |
||
+ | --- Gets the attack entry from weapon entry. |
||
− | function p.doPlural(Text, Value) |
||
+ | -- @function p._getAttack |
||
− | if (tonumber(Value) == 1) then |
||
+ | -- @param {table} weap Weapon entry |
||
− | Text = string.gsub(Text, "(<.+>)", "") |
||
+ | -- @param[opt] {number|table} atk Attacks table index or Attack entry |
||
− | else |
||
+ | -- @return {table} A single weapon+attack struct |
||
− | Text = string.gsub(Text, "<(.+)>", "%1") |
||
+ | local function getWeaponAttack(weap, atk) |
||
− | end |
||
+ | if type(atk) == 'number' then return StatObject.getStruct2(weap,weap.Attacks[atk]) end |
||
− | return Text |
||
+ | if weap.AttackName then return weap end |
||
+ | if type(atk) == 'table' then return StatObject.getStruct2(weap,atk) end |
||
+ | local key = atk or weap['_TooltipAttackDisplay'] or 1 |
||
+ | if weap.Attacks == nil then |
||
+ | error('p._getWeaponAttack(weap, atk): Attacks table is nil in '..mw.dumpObject(weap)) |
||
+ | end |
||
+ | return StatObject.getStruct2(weap,weap.Attacks[key]) |
||
end |
end |
||
+ | p._getAttack = getWeaponAttack |
||
+ | p._getWeaponAttack = getWeaponAttack |
||
− | function p. |
+ | function p._statRead(w, a, ...) |
+ | return statRead(getWeaponAttack(w, a), ...) |
||
− | 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 |
end |
||
+ | function p._statFormat(w, a, ...) |
||
− | |||
+ | return statFormat(getWeaponAttack(w, a), ...) |
||
− | function p.buildName(BaseName, Variant) |
||
+ | end |
||
− | if (Variant == nil or Variant == 'Base' or Variant == '') then |
||
+ | function p.stat(frame) |
||
− | return BaseName |
||
+ | return p._statFormat(p._getWeapon(frame.args[1] or 'Skana Prime'), nil, frame.args[2] or 'Name') |
||
− | elseif (Variant == "MK1") then |
||
− | return "MK1-" .. BaseName |
||
− | else |
||
− | return BaseName .. ' ' .. Variant |
||
− | end |
||
end |
end |
||
+ | -- Wrapper function for use in StatObject |
||
− | -- It's a bit of a mess, but this is for compressing a list with variants |
||
+ | local function dmgTooltip(damageType) |
||
− | -- So if a list has Braton, Braton Prime, and MK1-Braton it'll list as |
||
+ | return Tooltip.full(damageType, 'DamageTypes') |
||
− | -- 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 = Tooltip._tooltipText(baseName, 'Weapon') |
||
− | -- 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 .. |
||
− | Tooltip._tooltipText( |
||
− | p.buildName(baseName, varName), |
||
− | 'Weapon', varName) |
||
− | count = count + 1 |
||
− | end |
||
− | end |
||
− | thisRow = thisRow .. ')' |
||
− | end |
||
− | table.insert(result, thisRow) |
||
− | else |
||
− | for i, varName in pairs(variants) do |
||
− | table.insert(result, Tooltip._tooltipText( |
||
− | p.buildName(baseName, varName), 'Weapon')) |
||
− | end |
||
− | end |
||
− | end |
||
− | return result |
||
end |
end |
||
+ | -- Defining getters/attributes whose names match the associated database key or some custom derived attribute. |
||
− | function p.getWeapon(WeapName) |
||
+ | -- Index key will be name of getter function and can be mapped to a single value (getter definition) |
||
− | local weapon = WeaponData["Weapons"][WeapName] |
||
+ | -- or a table with two values (getter and format function definitions) |
||
+ | -- Cheatsheet on adding new keys: |
||
− | if weapon ~= nil and weapon.Name == WeapName then |
||
+ | -- StatName = default value -> Get raw value with the same StatName from M:Weapons/data and with no additional formatting (aka default formatting) |
||
− | return weapon |
||
+ | -- StatName = function(self) return self.StatName + 1 end -> Define custom getter function and use default formatting |
||
− | else |
||
+ | -- StatName = { default value, '%.2f' } -> Get raw value value with same StatName from M:Weapons/data and use format string for formatting |
||
− | for key, Weapon in Shared.skpairs(WeaponData["Weapons"]) do |
||
+ | -- StatName = { function(self) return ... end, '%.2f' } -> Define custom getter function and use format string for formatting |
||
− | if (Weapon.Name == WeapName or key == WeapName) then |
||
+ | -- StatName = { function(self) return ... end, function(self, returnValue1, returnValue2, ...) return tostring(returnValue) end } - > Define custom getter and format functions |
||
− | return Weapon |
||
+ | -- (Note that format function will pass in return value(s) from getter as well as object self) |
||
− | end |
||
− | end |
||
− | end |
||
+ | -- TODO: Put StatObject keys in alphabetical order for navigation |
||
− | return nil |
||
+ | StatObject.default = { |
||
+ | AttackName = 'Normal Attack', |
||
+ | AmmoCost = nil, |
||
+ | AmmoPickup = function(weapAtk) |
||
+ | return weapAtk['AmmoPickup'] or |
||
+ | weapAtk['Slot'] == 'Principale' and 80 or |
||
+ | weapAtk['Slot'] == 'Secondaire' and 40 or |
||
+ | weapAtk['Slot'] == 'Arch-Fusil (Atmosphère)' and 1000 or |
||
+ | 0 |
||
+ | end, |
||
+ | DamageBias = { |
||
+ | function(weapAtk) |
||
+ | if not weapAtk.Damage then |
||
+ | error('DamageBias: no Attack.Damage') |
||
+ | return 0, 0, 0 |
||
+ | end |
||
+ | local total, bestdmg, bestdt = 0, 0, nil |
||
+ | for dt, dmg in pairs(weapAtk.Damage) do |
||
+ | local dmg = dmg |
||
+ | if dmg >= bestdmg then |
||
+ | bestdmg, bestdt = dmg, dt |
||
+ | end |
||
+ | total = total + dmg |
||
+ | end |
||
+ | return StatObject.ucacheIn(weapAtk, 'DamageBias', { bestdmg / total, bestdt, total }) |
||
+ | end, |
||
+ | { percent, passes(dmgTooltip), '' } |
||
+ | }, |
||
+ | BiasPortion = { indexes('DamageBias', 1), percent }, |
||
+ | BiasType = { indexes('DamageBias', 2), function(self, biasType) return Tooltip.icon(biasType, 'DamageTypes') end }, |
||
+ | BaseDamage = { indexes('DamageBias', 3), '%.2f' }, |
||
+ | -- More precise damage values to 4 decimal places for PvP since PvP damage is calculated |
||
+ | -- based on a floating-point scalar. Damage quantization is more relevant in PvP so more |
||
+ | -- precise numbers needed. |
||
+ | PvPBaseDamage = { indexes('DamageBias', 3), '%.4f' }, |
||
+ | TotalDamage = { function(weapAtk) |
||
+ | return statRead(weapAtk, 'BaseDamage') * statRead(weapAtk, 'Multishot') |
||
+ | end, passes(Math.formatnum) |
||
+ | }, |
||
+ | -- Including max +60% Progenitor bonus for Kuva/Tenet weapons |
||
+ | TotalDamageWithProgenBonus = { function(weapAtk) |
||
+ | return statRead(weapAtk, 'TotalDamage') * (statRead(weapAtk, 'IsLichWeapon') and 1.6 or 1) |
||
+ | end, passes(Math.formatnum) |
||
+ | }, |
||
+ | ChargeTime = { 0, '%.1f s' }, |
||
+ | ExplosionDelay = { 0, '%.1f s' }, |
||
+ | ExtraHeadshotDmg = { 0, percents('+%.2f%%') }, |
||
+ | Falloff = { |
||
+ | function(weapAtk) |
||
+ | local fo = weapAtk['Falloff'] or {} |
||
+ | return fo.StartRange or 0, fo.EndRange or math.huge, 1 - (fo.Reduction or 1) |
||
+ | end, |
||
+ | { '%.1f m (100%%) -', '%.1f m', percents('(%.2f%%)') } |
||
+ | }, |
||
+ | FalloffStart = { indexes('Falloff', 1), '%.1f m' }, |
||
+ | FalloffEnd = { indexes('Falloff', 2), '%.1f m' }, |
||
+ | -- Damage reduction from falloff instead of damage multiplier |
||
+ | FalloffReduction = { function(weapAtk) |
||
+ | local _, _, falloff = statRead(weapAtk, 'Falloff') |
||
+ | return 1 - falloff |
||
+ | end, percent |
||
+ | }, |
||
+ | FalloffRate = { function(weapAtk) |
||
+ | local startdist,enddist,endpercent = statRead(weapAtk, 'Falloff') |
||
+ | return -(enddist-startdist)/(endpercent-1) |
||
+ | end, '%.1fm/%%' |
||
+ | }, |
||
+ | HeadshotMultiplier = { 1, '%.1fx' }, |
||
+ | Multishot = 1, |
||
+ | PunchThrough = { 0, '%.1f m' }, |
||
+ | ShotSpeed = { nil, function(self, shotSpeed) |
||
+ | if shotSpeed == nil or "?" then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return ('%.1f m/s'):format(shotSpeed) |
||
end |
end |
||
+ | }, |
||
− | |||
+ | BurstDelay = { 0, '%.4f s' }, |
||
− | local function checkWeapon(weap, weapName, conclave) |
||
+ | BurstReloadDelay = { 0, '%.2f s' }, |
||
− | if weap == nil or type(weap) ~= 'table' then |
||
+ | BurstsPerSec = { function(weapAtk) |
||
− | if conclave then |
||
+ | -- There is no delay after last shot in burst |
||
− | return p.getConclaveWeapon(weapName) |
||
+ | return 1 / ( (1 / statRead(weapAtk, 'FireRate') ) + statRead(weapAtk, 'BurstDelay') * ( statRead(weapAtk, 'BurstCount') - 1) ) |
||
− | else |
||
+ | end, '%.2f rafales/sec' }, |
||
− | return p.getWeapon(weapName) |
||
+ | CritChance = { 0, percent }, |
||
− | end |
||
+ | CritMultiplier = { 1, '%.2fx' }, |
||
− | elseif type(weap) == 'table' then |
||
+ | ForcedProcs = { unpacks('ForcedProcs'), function(s, ...) |
||
− | return weap |
||
+ | local procs = { ... } |
||
− | end |
||
+ | if procs[1] == nil then |
||
+ | return 'Aucun statut forcé' |
||
+ | end |
||
+ | local result = {} |
||
+ | for _, proc in ipairs(procs) do |
||
+ | table.insert(result, Tooltip.full(proc, 'DamageTypes')) |
||
+ | end |
||
+ | return table.concat(result, ', ') |
||
end |
end |
||
+ | }, |
||
− | |||
+ | Radius = { 0, '%.1f m' }, |
||
− | function p.weaponExists(frame) |
||
+ | StatusChance = { 0, percent }, |
||
− | local weapName = frame.args ~= nil and frame.args[1] or nil |
||
+ | Disposition = { |
||
− | |||
+ | function(weap) |
||
− | return p._weaponExists(weapName) |
||
+ | local d = weap['Disposition'] |
||
+ | -- Returning a categorical bin value of 1, 2, 3, 4, or 5 based on where disposition value |
||
+ | -- is on the continuous scale of 0.5-1.55. If disposition value is nil then return 0 |
||
+ | return d or 0, type(d)=='number' and math.floor(5*(d-.3+.009*(d<1 and 1 or -1))) or 0 |
||
+ | end, |
||
+ | function(s, v, d) |
||
+ | return StatObject.default.Dispo[2](s, d)..(' (%.2fx)'):format(v) |
||
+ | end |
||
+ | }, |
||
+ | Dispo = { indexes('Disposition', 2), function(s, d) |
||
+ | if d and d == d and d > 0 then |
||
+ | return ('●'):rep(math.min(d, 5))..('○'):rep(5 - d) |
||
+ | end |
||
+ | return '×××××' -- '●○×' --> E2978F E2978B C397 |
||
+ | end }, |
||
+ | Introduced = { function(weap) |
||
+ | return weap['Introduced'] and Version._getVersion(weap['Introduced'])['Name'] or 'N/A' |
||
+ | end, passes(Version._getVersionLink) |
||
+ | }, |
||
+ | IntroducedDate = function(weap) |
||
+ | return weap['Introduced'] and Version._getVersionDate(weap['Introduced']) or 'N/A' |
||
+ | end, |
||
+ | IsLichWeapon = function(weap) |
||
+ | return weap['IsLichWeapon'] and true or false |
||
+ | end, |
||
+ | Mastery = 0, |
||
+ | Link = { nil, '[[%s]]' }, |
||
+ | Name = { nil, function(s, v) return Tooltip.full(v, 'Weapons') end }, |
||
+ | InternalName = '', |
||
+ | NameLink = { function(weap) return weap.Link, weap.Name end, '[[%s|%s]]' }, |
||
+ | Polarities = { nil, passes(Polarity._pols) }, |
||
+ | Traits = { unpacks('Traits'), { sep = ', ' } }, |
||
+ | -- Default nil b/c some attacks don't have an associated accuracy/spread value (like AoE explosions) |
||
+ | Accuracy = { nil, function(self, value) |
||
+ | if (value == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return value |
||
end |
end |
||
+ | }, |
||
− | |||
+ | -- Inverse of accuracy. Spread of 1 equates to no spread. |
||
− | function p._weaponExists(weapName, weap) |
||
+ | -- Alternatively, it can be calculated by the average of min and max spread, see AvgSpread getter. |
||
− | local weap = checkWeapon(weap, weapName) |
||
+ | Spread = { function(weapAtk) |
||
− | |||
+ | local accuracy = statRead(weapAtk, 'Accuracy') |
||
− | if weapName == 'Épées Versatiles Sombres' then |
||
+ | return (accuracy == nil) and nil or 100 / accuracy |
||
− | return true |
||
+ | end, function(self, value) |
||
− | elseif weap then |
||
+ | if (value == nil) then |
||
− | return true |
||
+ | return 'N/A' |
||
− | end |
||
+ | end |
||
− | |||
+ | return value |
||
− | if weapName == nil then |
||
− | return 'Enter weapon name.' |
||
− | elseif weap == nil then |
||
− | return 'No weapon ' .. weapName .. ' found.' |
||
− | end |
||
− | |||
end |
end |
||
+ | }, |
||
− | |||
+ | AmmoType = function(weapAtk) |
||
− | function p.getLink(frame) |
||
+ | return weapAtk['AmmoType'] or ({ |
||
− | local weapName = frame.args ~= nil and frame.args[1] or nil |
||
+ | ['Arch-Fusil (Atmosphère)'] = 'Lourde', |
||
− | if weapName == nil then return 'Enter weapon name.' end |
||
+ | ['Secondaire'] = 'Secondaire', |
||
− | |||
+ | ['Principale'] = 'Principale' |
||
− | return p._getLink(weapName) |
||
+ | })[weapAtk['Slot']] or 'None' |
||
+ | end, |
||
+ | -- Not all weapons have an Exilus slot so default to nil |
||
+ | ExilusPolarity = { nil, function(self, exilusPolarity) |
||
+ | if (exilusPolarity == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return Polarity._polarity(exilusPolarity) |
||
end |
end |
||
+ | }, |
||
− | |||
+ | Magazine = 1, |
||
− | function p._getLink(weapName, weap) |
||
+ | AmmoMax = { function(weapAtk) |
||
− | local weap = checkWeapon(weap, weapName) |
||
+ | if statRead(weapAtk, 'IsMelee') then |
||
− | local exists = p._weaponExists(weapName, weap) |
||
+ | return nil |
||
− | if weapName == "Épées Versatiles Sombres" then |
||
+ | end |
||
− | return "Épées Versatiles Sombres" |
||
+ | return weapAtk['AmmoMax'] or math.huge |
||
− | elseif exists == true then |
||
+ | end, passes(Math.formatnum) |
||
− | local temp = weap.Link |
||
+ | }, |
||
− | if weap.Type == "Arch-Fusil (Atmosphère)" then |
||
+ | Range = { function(weapAtk) |
||
− | local atmoTemp = Shared.splitString(weap.Name, "%s") |
||
+ | return weapAtk['Range'] or statRead(weapAtk, 'ShotType') == 'Impact-direct' and 300 or 0 |
||
− | local atmoCount = Shared.tableCount(atmoTemp) |
||
+ | end, '%.1f m' |
||
− | if atmoCount == 2 then |
||
+ | }, |
||
− | return atmoTemp[1] |
||
+ | Reload = { ors('Reload', 'RechargeTime', 0), '%.2f s' }, |
||
− | elseif atmoCount >= 2 then |
||
+ | RechargeTime = { function(weapAtk) |
||
− | return table.concat(atmoTemp, ' ', 1, (atmoCount - 1)) |
||
+ | return statRead(weapAtk, 'ReloadStyle'):find'[Rr]egen' and statRead(weapAtk, 'Magazine') / statRead(weapAtk, 'ReloadRate') or nil |
||
− | end |
||
+ | end, '%.2f s' |
||
− | return weap.Name |
||
+ | }, |
||
− | elseif temp then |
||
+ | ReloadRate = { 0, '%.2f balles/sec' }, -- Used for rechargeable weapons; not necessarily inverse of reload time b/c of presence of reload delay |
||
− | return temp |
||
+ | ReloadDelay = { function(weapAtk) |
||
− | else |
||
+ | return weapAtk['ReloadDelay'] or 0 |
||
− | return weap.Name |
||
+ | end, '%.2f s' |
||
− | end |
||
+ | }, |
||
− | elseif weapName == nil then |
||
+ | ReloadDelayEmpty = { ors('ReloadDelayEmpty', 'ReloadDelay'), '%.2f s' }, |
||
− | return false |
||
+ | -- Reload speed will be calculated as the inverse of reload time for purposes |
||
− | else |
||
+ | -- of keeping how we rank stats consistent for [[Module:Weapons/preprocess]] |
||
− | return false |
||
+ | -- (larger number = higher stat; a short reload time can be expressed as fast reload |
||
− | end |
||
+ | -- speed which would be a larger value in magnitude) |
||
+ | ReloadSpeed = { function(weapAtk) |
||
+ | return 1 / statRead(weapAtk, 'Reload') |
||
+ | end, function(str, reloadSpeed) |
||
+ | return string.format('%.2f%% progression de recharge par seconde', reloadSpeed * 100) |
||
+ | end }, |
||
+ | ReloadStyle = 'Magazine', |
||
+ | Spool = { 0, '%d balles' }, |
||
+ | SpoolStartFireRate = { 0, '%.1fx' }, -- scalar that is applied to fire rate stat for auto-spool weapons |
||
+ | AvgSpread = { function(weapAtk) |
||
+ | local minSpread = statRead(weapAtk, 'MinSpread') |
||
+ | local maxSpread = statRead(weapAtk, 'MaxSpread') |
||
+ | if (minSpread == nil) then |
||
+ | return nil |
||
+ | end |
||
+ | return (minSpread + maxSpread) / 2 |
||
+ | end, function(self, value) |
||
+ | if (value == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return ('%.2f°'):format(value) |
||
+ | end |
||
+ | }, |
||
+ | -- Default nil b/c some attacks don't have an associated accuracy/spread value (like AoE explosions) |
||
+ | MinSpread = { nil, function(self, value) |
||
+ | if (value == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return ('%.2f°'):format(value) |
||
+ | end |
||
+ | }, |
||
+ | MaxSpread = { nil, function(self, value) |
||
+ | if (value == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return ('%.2f°'):format(value) |
||
+ | end |
||
+ | }, |
||
+ | Trigger = 'N/A', |
||
+ | BlockAngle = { 0, '%d°' }, |
||
+ | ComboDur = { 0, '%.1f s' }, |
||
+ | FollowThrough = { 0, '%.1fx' }, |
||
+ | HeavyAttack = { 0, passes(Math.formatnum) }, |
||
+ | HeavySlamAttack = { 0, passes(Math.formatnum) }, |
||
+ | HeavyRadialDmg = { 0, passes(Math.formatnum) }, |
||
+ | HeavySlamRadius = { 0, '%.1f m' }, |
||
+ | MeleeRange = { 0, '%.2f m' }, |
||
+ | SlamAttack = { 0, passes(Math.formatnum) }, |
||
+ | SlamRadialDmg = { function(weapAtk) |
||
+ | return weapAtk.SlamRadialDmg or 0, statRead(weapAtk, 'SlamRadialElement') |
||
+ | end, function(self, dmg, elem) |
||
+ | if elem then |
||
+ | return Tooltip.icon(elem, 'DamageTypes')..' '..Math.formatnum(dmg) |
||
+ | end |
||
+ | return Math.formatnum(dmg) |
||
end |
end |
||
+ | }, |
||
− | |||
+ | SlamRadialElement = { nil, function(self, value) |
||
− | function p.getConclaveWeapon(WeapName) |
||
+ | return value ~= nil and Tooltip.full(value, 'DamageTypes') or 'Même répartition des types de dégâts que pour l\'attaque normale' |
||
− | local weapon = ConclaveData["Weapons"][WeapName] |
||
− | |||
− | if weapon ~= nil and weapon.Name == WeapName then |
||
− | return weapon |
||
− | else |
||
− | for key, Weapon in Shared.skpairs(ConclaveData["Weapons"]) do |
||
− | if (Weapon.Name == WeapName or key == WeapName) then |
||
− | return Weapon |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | return nil |
||
end |
end |
||
+ | }, |
||
− | |||
+ | -- Slam radial forced proc(s) |
||
− | function p.isMelee(frame) |
||
+ | SlamRadialProcs = { nil, function(self, proc) |
||
− | if (frame == nil) then return nil end |
||
+ | if type(proc)=='table' then |
||
− | local Weapon = frame.args ~= nil and frame.args[1] or frame |
||
+ | local result = {} |
||
− | if (type(Weapon) == "string") then Weapon = p.getWeapon(Weapon) end |
||
+ | for _, elem in ipairs(proc) do |
||
− | |||
+ | table.insert(result, Tooltip.full(elem, 'DamageTypes')) |
||
− | if (Weapon == nil) then return nil end |
||
+ | end |
||
− | |||
+ | return table.concat(result, '<br />') |
||
− | if (Weapon.Type ~= nil and |
||
+ | else |
||
− | (Weapon.Type == "Mêlée" or Weapon.Type == "Arch-Mêlée")) then |
||
− | + | return 'N/A' |
|
− | + | end |
|
− | |||
− | return nil |
||
end |
end |
||
+ | }, |
||
− | |||
+ | SlamRadius = { 0, '%.1f m' }, |
||
− | function p.isArchwing(frame) |
||
+ | SlideAttack = { function(weapAtk) |
||
− | if (frame == nil) then return nil end |
||
+ | return weapAtk.SlamRadialDmg or 0, statRead(weapAtk, 'SlideElement') |
||
− | local Weapon = frame.args ~= nil and frame.args[1] or frame |
||
+ | end, function(self, dmg, elem) |
||
− | if (type(Weapon) == "string") then Weapon = p.getWeapon(Weapon) end |
||
+ | if elem then |
||
− | |||
+ | return Tooltip.icon(elem, 'DamageTypes')..' '..Math.formatnum(dmg) |
||
− | if (Weapon == nil) then return nil end |
||
+ | end |
||
− | |||
+ | return Math.formatnum(dmg) |
||
− | if (Weapon.Type ~= nil and |
||
− | (Weapon.Type == "Arch-Fusil" or Weapon.Type == "Arch-Mêlée")) then |
||
− | return "yes" |
||
− | end |
||
− | |||
− | return nil |
||
end |
end |
||
+ | }, |
||
− | |||
+ | SlideElement = { nil, function(self, value) |
||
− | local function getAttack(Weapon, AttackType) |
||
+ | return value ~= nil and Tooltip.full(value, 'DamageTypes') or 'Même répartition des types de dégâts que pour l\'attaque normale' |
||
− | 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 |
||
− | elseif (AttackType == "MELEESLAM") then |
||
− | return Weapon.MeleeSlam |
||
− | elseif (AttackType == "MELEEHEAVY") then |
||
− | return Weapon.MeleeHeavy |
||
− | else |
||
− | return nil |
||
− | end |
||
end |
end |
||
+ | }, |
||
− | |||
− | + | --[[Stances = function(weapAtk) |
|
+ | if not statRead(weapAtk, 'IsMelee') then return end |
||
− | if (getAttack(Weapon, AttackType) ~= nil) then |
||
+ | return Stances._getAllStancesSameType(statRead(weapAtk, "Class")) |
||
− | return true |
||
+ | -- ^ currently a local function |
||
− | else |
||
+ | end,--]] |
||
− | return nil |
||
+ | -- Not all weapons have an Stance slot so default to nil |
||
− | end |
||
+ | StancePolarity = { nil, function(self, stancePolarity) |
||
+ | if (stancePolarity == nil) then |
||
+ | return 'N/A' |
||
+ | end |
||
+ | return Polarity._polarity(stancePolarity) |
||
end |
end |
||
+ | }, |
||
+ | SweepRadius = { 0, '%.2f m' }, |
||
+ | WindUp = { 0, '%.1f s' }, |
||
+ | BurstCount = 1, |
||
+ | -- Average crit/proc count from a single attack input |
||
+ | AvgCritCount = function(weapAtk) |
||
+ | return statRead(weapAtk, 'CritChance') * statRead(weapAtk, 'Multishot') |
||
+ | end, |
||
+ | AvgCritPerSec = function(weapAtk) |
||
+ | return statRead(weapAtk, 'AvgCritCount') * statRead(weapAtk, 'EffectiveFireRate') |
||
+ | end, |
||
+ | AvgProcCount = function(weapAtk) |
||
+ | return ( statRead(weapAtk, 'StatusChance') + Table.size(weapAtk['ForcedProcs'] or {}) ) * statRead(weapAtk, 'Multishot') |
||
+ | end, |
||
+ | AvgProcPerSec = function(weapAtk) |
||
+ | return statRead(weapAtk, 'AvgProcCount') * statRead(weapAtk, 'EffectiveFireRate') |
||
+ | end, |
||
+ | InterShotTime = function(weapAtk) |
||
+ | local v = statRead(weapAtk, 'Magazine') == 1 and statRead(weapAtk, 'Reload') + statRead(weapAtk, 'ReloadDelayEmpty') or 0 |
||
+ | if v == 0 then v = 1 / statRead(weapAtk, 'FireRate') end |
||
+ | return v |
||
+ | end, |
||
+ | EffectiveFireRate = function(weapAtk) |
||
+ | return 1 / ( statRead(weapAtk, 'ChargeTime') + statRead(weapAtk, 'InterShotTime') ) |
||
+ | end, |
||
+ | ShotsPerMag = function(weapAtk) |
||
+ | -- Default to 1 "ammo cost" even if attack does not directly consume ammo (e.g. AoE hits, speargun throws, etc.) |
||
+ | return math.floor(statRead(weapAtk, 'Magazine') / (statRead(weapAtk, 'AmmoCost') or 1)) |
||
+ | end, |
||
+ | FireRate = { function(weapAtk) |
||
+ | local dataFireRate = weapAtk['FireRate'] |
||
+ | if dataFireRate then return dataFireRate end |
||
+ | -- TODO: Think we can safely remove this calculation of FireRate from BurstFireRate, BurstDelay, and BurstCount |
||
+ | -- for burst-fire attacks since FireRate is also included for those |
||
+ | mw.log('calcul de la cadence de tir depuis les stats de rafales pour '..statRead(weapAtk, 'Name')) |
||
+ | local count = statRead(weapAtk, 'BurstCount') |
||
+ | local fireRate = count / (1 / statRead(weapAtk, 'BurstFireRate') + count * statRead(weapAtk, 'BurstDelay')) |
||
+ | return fireRate |
||
+ | end, '%.3f tirs/sec' |
||
+ | }, |
||
+ | BurstFireRate = { function(weapAtk) |
||
+ | return 1 / statRead(weapAtk, 'BurstDelay') |
||
+ | end, '%.2f tirs/sec' |
||
+ | }, |
||
+ | --[[ |
||
+ | Describing what happens when a gun in WARFRAME is fired using player-made terminology: |
||
+ | A particular gun consumes a set number of ammo in order to fire a set number of shots |
||
− | local function dontHasAttack(Weapon, AttackType) |
||
+ | on a single player input for a particular attack. |
||
− | if (getAttack(Weapon, AttackType) ~= nil) then |
||
− | return nil |
||
− | else |
||
− | return true |
||
− | end |
||
− | end |
||
+ | A single player input is defined as: |
||
− | function p.hasAttack(frame) |
||
+ | * a single attack button press for semi-auto and burst trigger weapons |
||
− | local WeapName = frame.args[1] |
||
+ | * the moment the next shot is being fired when the attack button is being held for automatic/held trigger weapons |
||
− | local AttackName = frame.args[2] |
||
+ | * the action of holding the attack button for charge trigger weapons |
||
+ | * for duplex-fire trigger weapons, the hold and release of the attack button counts as two inputs |
||
+ | A shot is defined as the base unit of attack of a weapon when unmodded. |
||
− | if (WeapName == nil) then |
||
+ | * A single attack input can launch several shots as in the case of burst-fire weapons. |
||
− | return "ERREUR: Il n'y a pas le nom de l'arme" |
||
+ | * A single shot can shoot more than one projectile, affected by the multishot stat, as in the case of shotguns. |
||
− | elseif (AttackName == nil) then |
||
+ | * A single shot can consume more than one unit of ammo (e.g. Tenora's alt-fire) or |
||
− | AttackName = "Normal" |
||
+ | less than one unit of ammo (e.g. Ignis and most continuous weapons). |
||
− | end |
||
+ | A gun can have multiple attacks which can be triggered using different buttons |
||
− | local Weapon = p.getWeapon(WeapName) |
||
+ | and/or types of button inputs (e.g. pressing vs. holding) |
||
− | if (Weapon == nil) then |
||
+ | ]]-- |
||
− | return "ERREUR: L'arme " .. WeapName .. " n'a pas été trouvé" |
||
+ | CalcDamage = function(weapAtk) |
||
− | end |
||
+ | local weapon, attack = weapAtk, weapAtk |
||
+ | -- Count |
||
+ | -- How many shots are fired in a single player input |
||
+ | local tapShots = statRead(weapAtk, 'BurstCount') |
||
+ | -- How many individual player inputs can occur before depleting a magazine |
||
+ | local magTaps = statRead(weapAtk, 'ShotsPerMag') |
||
+ | -- How many additional projectiles are fired per ammo |
||
+ | local multishot = statRead(weapAtk, 'Multishot') |
||
+ | -- How much ammo is contained in the magazine |
||
+ | local magazine = statRead(weapAtk, 'Magazine') |
||
+ | -- How much ammo can be drawn from reserves (or?, how much ammo can be used without picking up more) |
||
+ | local ammoMax = statRead(weapAtk, 'AmmoMax') |
||
+ | -- Time^-1 |
||
− | return hasAttack(Weapon, AttackName) |
||
+ | local fireRate = statRead(weapAtk, 'FireRate') |
||
− | end |
||
+ | -- Time |
||
+ | local shotTime = statRead(weapAtk, 'InterShotTime') |
||
+ | local chargeTime = statRead(weapAtk, 'ChargeTime') |
||
+ | local burstDelayTime = statRead(weapAtk, 'BurstDelay') |
||
+ | local reloadDelayTime = statRead(weapAtk, 'ReloadDelayEmpty') |
||
+ | local reloadTime = statRead(weapAtk, 'Reload') |
||
+ | local tapTime = chargeTime + (tapShots - 1) * burstDelayTime |
||
+ | -- tapTime: The time between the last shot fired and the next valid attack input |
||
+ | -- (omitting latency of course). |
||
+ | -- Note that first shot of any non-charge trigger attack is instantenous |
||
+ | local magDepletionTime = magTaps * tapTime |
||
+ | if magDepletionTime == 0 then -- If attack is not a charged attack |
||
+ | if shotTime == 0 then |
||
+ | shotTime = 1 / fireRate |
||
+ | end |
||
+ | magDepletionTime = magTaps / fireRate |
||
+ | end |
||
+ | local shotDelayTime = math.max(0, shotTime - tapTime) |
||
+ | -- Multiplier |
||
− | local function hasMultipleTypes(Attack) |
||
+ | local maxProgenitorBonus = statRead(weapAtk, 'IsLichWeapon') and 1.6 or 1 |
||
− | local typeCount = 0 |
||
+ | local avgCritMult = 1 + (statRead(weapAtk, 'CritMultiplier') - 1) * statRead(weapAtk, 'CritChance') |
||
− | if (Attack ~= nil and Attack.Damage ~= nil) then |
||
+ | -- Damage |
||
− | for key, dmg in Shared.skpairs(Attack.Damage) do |
||
+ | local biasPortion, biasType, hitDamage = statRead(weapAtk, 'DamageBias') |
||
− | if (dmg > 0) then typeCount = typeCount + 1 end |
||
+ | |||
− | end |
||
+ | local avgDmgOnTap = hitDamage * avgCritMult * multishot * tapShots * maxProgenitorBonus |
||
− | end |
||
+ | local avgDmgPerMag = avgDmgOnTap * magTaps |
||
− | if (typeCount > 1) then |
||
+ | |||
− | return "yes" |
||
+ | -- 1 is needed b/c one whole magazine is not included in reserve ammo count |
||
− | else |
||
+ | -- If there is no reserve ammo, that means that weapon can deal an infinite amount of damage theoretically |
||
− | return nil |
||
+ | local avgLifetimeDmg = (ammoMax ~= nil) and avgDmgPerMag * (1 + (ammoMax / magazine)) or math.huge |
||
− | end |
||
+ | |||
+ | -- Damage / Time |
||
+ | local baseDps = hitDamage * multishot / shotTime |
||
+ | local avgSustainedDps = avgDmgPerMag / (magDepletionTime + reloadDelayTime + reloadTime) / tapShots |
||
+ | local avgBurstDps = avgDmgOnTap / (tapTime + shotDelayTime) / tapShots |
||
+ | -- Note that burst DPS can also be calculated as such: |
||
+ | -- local avgBurstDps = (hitDamage * avgCritMults * maxProgenitorBonus) * multishot / shotTime |
||
+ | -- local avgBurstDps = avgDmgPerMag / magDepletionTime |
||
+ | |||
+ | return StatObject.ucacheIn(weapAtk, 'CalcDamage', |
||
+ | { hitDamage, avgDmgOnTap, avgBurstDps, avgSustainedDps, avgLifetimeDmg, baseDps, avgDmgPerMag } |
||
+ | ) |
||
+ | end, |
||
+ | ShotDmg = indexes('CalcDamage', 1), -- Total damage per projectile |
||
+ | AvgShotDmg = indexes('CalcDamage', 2), AvgTapDmg = indexes('CalcDamage', 2), -- Average total damage per each input button |
||
+ | BurstDps = indexes('CalcDamage', 3), -- Average burst damage per second/DPS w/o reloading |
||
+ | SustainedDps = indexes('CalcDamage', 4), -- Average sustained damage per second/DPS w/ reloading |
||
+ | LifetimeDmg = indexes('CalcDamage', 5), -- Average total damage from entire ammo pool |
||
+ | BaseDps = indexes('CalcDamage', 6), -- Base damage per second w/ multishot w/o crit |
||
+ | MagDmg = indexes('CalcDamage', 7), -- Average total damage per magazine |
||
+ | -- Average damage scaled by melee attack speed multiplier (numerator of melee DPS w/o accounting for stances and animation time) |
||
+ | AvgDmgWithAnimSpeedMulti = function(weapAtk) |
||
+ | if statRead(weapAtk, 'IsMelee') then |
||
+ | -- Some melee weapons have attacks with multishot like Redeemer, Vastilok, and Quassus |
||
+ | return statRead(weapAtk, 'BaseDamage') * statRead(weapAtk, 'Multishot') * statRead(weapAtk, 'AttackSpeed') |
||
+ | end |
||
+ | return 0 |
||
+ | end, |
||
+ | AttackSpeed = { --[[ors('AttackSpeed', 'FireRate')]]function(weapAtk) |
||
+ | if not statRead(weapAtk, 'IsMelee') then |
||
+ | error('AttackSpeed: Cannot get AttackSpeed attribute for a non-melee weapon; use p.statRead(weapAtk, "FireRate") instead') |
||
+ | end |
||
+ | return statRead(weapAtk, 'FireRate') |
||
+ | end, '%.2fx vitesse d\'animation' |
||
+ | }, |
||
+ | IsMelee = function(weapAtk) return statRead(weapAtk, 'Slot'):find('Mêlée') ~= nil end, |
||
+ | IsSilent = ors('IsSilent', 'IsMelee', false), |
||
+ | HasAoEAttack = function(weap) |
||
+ | for i, attackEntry in pairs(weap['Attacks']) do |
||
+ | if attackEntry['ShotType'] == 'AoE' then |
||
+ | return true |
||
+ | end |
||
+ | end |
||
+ | return false |
||
+ | end, |
||
+ | Conclave = false, |
||
+ | Image = { 'Panel.png', '[[File:%s|link=]]' }, |
||
+ | Attacks = ors('Attacks', p._getAttack, {}), |
||
+ | Family = nil, |
||
+ | FamilyList = { function(weapAtk) |
||
+ | local family = statRead(weapAtk, 'Family') |
||
+ | -- assert(family, 'i have no Family :\'(') |
||
+ | if not family then return {weapAtk} end |
||
+ | -- return family, statRead(weapAtk, 'Slot') |
||
+ | local slot = statRead(weapAtk, 'Slot') |
||
+ | local result = {} |
||
+ | for _, w in pairs(WeaponData[slot] or error('FamilyList: no weapondata for slot '..(slot or '<nil>'))) do |
||
+ | if w.Family == family then |
||
+ | table.insert(result, w) |
||
+ | end |
||
+ | end |
||
+ | table.sort(result, function(a,b) return a.Name<b.Name end) |
||
+ | return result |
||
+ | end, function(self, result) |
||
+ | for i,w in ipairs(result) do |
||
+ | result[i]=Tooltip.full(w.Name, 'Weapons', w) |
||
+ | end |
||
+ | return table.concat(result, '<br />') |
||
end |
end |
||
+ | }, |
||
+ | BaseName = function(weapAtk) return weapAtk['BaseName'] or ({p._getVariant(statRead(weapAtk, 'Name'))})[3] end, |
||
+ | -- TODO: Add comments to Explosion function for readability |
||
+ | -- TODO: Do not rely on attack name to determine what AoE component is attached to which main direct hit component |
||
+ | ---^i suggest an explosion key with either the attack number of any corresponding explosion, nested attack tables, or some other way to make a tree |
||
+ | -- TODO: Use ShotType = "AoE" to determine if attack entry is AoE |
||
+ | Explosion = function(weapAtk) |
||
+ | local weap, atk = weapAtk, weapAtk |
||
+ | -- tbh this is a mess |
||
+ | local explosion = weapAtk['Explosion'] or statRead(weapAtk, 'AttackName'):gsub(' Impact',''):gsub(' Contact','')..' Explosion' |
||
+ | if type(explosion) == 'string' then |
||
+ | explosion = weap.Attacks[tonumber(explosion:gsub('%D',''))] or explosion |
||
+ | elseif type(explosion) == 'number' then |
||
+ | explosion = weap.Attacks[explosion] or explosion |
||
+ | end |
||
+ | local explosions = {} |
||
+ | if type(explosion) ~= 'table' then |
||
+ | for i, v in ipairs(weap.Attacks) do |
||
+ | if p._statRead(weapAtk, v, 'AttackName'):find 'xplosion' then |
||
+ | if p._statRead(weapAtk, v, 'AttackName') == explosion then |
||
+ | explosions[1] = nil |
||
+ | explosion = v |
||
+ | break |
||
+ | end |
||
+ | table.insert(explosions, v) |
||
+ | end |
||
+ | end |
||
+ | explosion = explosions[1] or explosion |
||
+ | end |
||
+ | StatObject.pcacheIn(getWeaponAttack(weap, explosion), 'BaseAttack', atk) |
||
+ | return StatObject.pucacheIn(weapAtk, 'Explosion', explosion) |
||
+ | end, |
||
+ | IsVariant = function(weap) |
||
+ | return StatObject.pucacheIn(weap, 'IsVariant', p._isVariant(statRead(weap, 'Name'))) |
||
+ | end, |
||
+ | Variant = indexes('IsVariant', 2), |
||
+ | BaseName = indexes('IsVariant', 3), |
||
+ | Categories = { function(weapAtk) |
||
+ | local cats = { 'Armes' } |
||
+ | -- Adding editor-defined traits from M:Weapons/data |
||
+ | -- Note to make sure they have a proper category page associated with a trait |
||
+ | for _, trait in ipairs(weapAtk.Traits or {}) do |
||
− | function p.hasMultipleTypes(frame) |
||
− | + | local weapsTraitsMap = ({ |
|
+ | -- De fabrication / origines |
||
− | local AttackName = frame.args[2] |
||
+ | ["Tenno"] = { "Tenno", "Armes/Tennos" }, |
||
− | if (AttackName == nil) then AttackName = "Normal" end |
||
+ | ["Corpus"] = { "Corpus", "Armes/Corpus" }, |
||
− | local attack = getAttack(WeapName, AttackName) |
||
+ | ["Grineer"] = { "Grineer", "Armes/Grineers" }, |
||
− | return hasMultipleTypes(attack) |
||
+ | ["Infestée"] = { "Infestée", "Armes/Infestées" }, |
||
− | end |
||
+ | ["Orokin"] = { "Orokin", "Armes/Orokins" }, |
||
+ | ["Sentient"] = { "Sentient", "Armes/Sentients" }, |
||
+ | ["Entrati"] = { "Entrati", "Armes/Entratis" }, |
||
+ | ["Céphalon"] = { "Céphalon", "Armes/Céphalons" }, |
||
+ | -- Spéciales & Variantes |
||
+ | ["Incarnon"] = { "Armes/Incarnon" }, |
||
+ | ["Principe"] = { "Armes/Principe" }, |
||
+ | ["Prisma"] = { "Armes/Prisma" }, |
||
+ | ["Vandal"] = { "Armes/Vandal" }, |
||
+ | ["Wraith"] = { "Armes/Wraith" }, |
||
+ | ["MK1"] = { "Armes/MK1" }, |
||
+ | ["Signature"] = { "Armes/Signature" }, |
||
+ | ["Liche Kuva"] = { "Liche Kuva", "Armes/Liche Kuva" }, |
||
+ | -- Prime state |
||
+ | ["Prime"] = { "Prime", "Armes/Prime" }, |
||
+ | ["Vaultée"] = { "Prime Vault", "Armes/Vault" }, |
||
+ | ["Jamais Vaultée"] = { "Jamais en Vault" }, |
||
+ | -- Syndicats |
||
+ | ["Syndicats"] = { "Armes de Syndicats" }, |
||
+ | ["Arbitres de Hexis"] = { "Arbitres de Hexis" }, -- Telos |
||
+ | ["Céphalon Suda"] = { "Céphalon Suda" }, -- Synoid |
||
+ | ["Méridien d'Acier"] = { "Méridien d'Acier" }, -- Vaykor |
||
+ | ["Nouveau Loka"] = { "Nouveau Loka" }, -- Sancti |
||
+ | ["La Séquence Perrin"] = { "La Séquence Perrin" }, -- Secura |
||
+ | ["Voile Rouge"] = { "Voile Rouge" }, -- Rakta |
||
+ | ["Céphalon Simaris"] = { "Céphalon Simaris" }, -- Special |
||
+ | -- Armes de "Factions" / PNJ |
||
+ | ["Dax"] = { "Armes/Dax" }, |
||
+ | ["Duviri"] = { "Armes/Duviri" }, |
||
+ | ["Zariman"] = { "Armes/Zariman" }, |
||
+ | ["Cetus"] = { "Armes/Cetus" }, |
||
+ | ["Fortuna"] = { "Armes/Fortuna" }, |
||
+ | ["Puy de Cambion"] = { "Armes/Puy de Cambion" }, |
||
+ | ["Stalker"] = { "Stalker", "Armes/Stalker" }, |
||
+ | ["Baro"] = { "Offres de Baro Ki'Teer" }, |
||
+ | -- Autres |
||
+ | ["Dex"] = { "Armes/Dex" }, |
||
+ | ["Quête"] = { "Armes/Quêtes" }, |
||
+ | ["Fondateur"] = { "Fondateur", "Armes/Fondateur" }, |
||
+ | ["Invasions"] = { "Invasions", "Récompenses d'évènements", "Armes/Invasions", "Armes/Évènements" }, |
||
+ | ["Alertes Tactiques"] = { "Récompenses d'Alertes Tactiques" }, |
||
+ | })[trait] |
||
+ | |||
+ | if weapsTraitsMap then |
||
+ | for _, cat in ipairs(weapsTraitsMap) do |
||
+ | table.insert(cats, cat) |
||
+ | end |
||
+ | else |
||
+ | table.insert(cats, "Armes/Incomplètes") |
||
+ | end |
||
+ | end |
||
+ | -- DamageTypes categories |
||
− | function p.attackLoop(Weapon) |
||
+ | local bias = p._getValue(weapAtk, "BiasType") |
||
− | if (Weapon == nil) then return function() return nil end end |
||
+ | table.insert(cats, ({ |
||
− | local aType = "Normal" |
||
+ | -- Physic |
||
− | local iterator = function() |
||
+ | ["Impact"] = "Armes/Dégâts/Impact", |
||
− | if (aType == "Normal") then |
||
+ | ["Tranchant"] = "Armes/Dégâts/Tranchant", |
||
− | local attack = getAttack(Weapon, aType) |
||
+ | ["Perforation"] = "Armes/Dégâts/Perforation", |
||
− | aType = "Charge" |
||
+ | -- Elemental |
||
− | if attack ~= nil and attack.Damage ~= nil then |
||
+ | -- -- Main |
||
− | return "Normal", attack |
||
+ | ["Feu"] = "Armes/Dégâts/Feu", |
||
− | end |
||
+ | ["Glace"] = "Armes/Dégâts/Glace", |
||
− | end |
||
+ | ["Poison"] = "Armes/Dégâts/Poison", |
||
− | if (aType == "Charge") then |
||
+ | ["Électrique"] = "Armes/Dégâts/Électrique", |
||
− | local attack = getAttack(Weapon, aType) |
||
+ | -- -- Mixed |
||
− | aType = "Area" |
||
+ | ["Gaz"] = "Armes/Dégâts/Gaz", |
||
− | if attack ~= nil and attack.Damage ~= nil then |
||
+ | ["Viral"] = "Armes/Dégâts/Viral", |
||
− | return "Charge", attack |
||
+ | ["Corrosif"] = "Armes/Dégâts/Corrosif", |
||
− | end |
||
+ | ["Explosif"] = "Armes/Dégâts/Explosif", |
||
− | end |
||
+ | ["Radiation"] = "Armes/Dégâts/Radiation", |
||
− | if (aType == "Area") then |
||
+ | ["Magnétique"] = "Armes/Dégâts/Magnétique", |
||
− | local attack = getAttack(Weapon, aType) |
||
+ | -- -- Specials |
||
− | aType = "SecondaryArea" |
||
+ | ["Tau"] = "Armes/Dégâts/Tau", |
||
− | if attack ~= nil and attack.Damage ~= nil then |
||
+ | ["Brut"] = "Armes/Dégâts/Brut", |
||
− | return "Area", attack |
||
+ | ["Néant"] = "Armes/Dégâts/Néant", |
||
− | 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 |
||
+ | })[bias] or "Armes/Dégâts/Inconnus") |
||
− | return nil |
||
+ | |||
− | end |
||
+ | local class = p._getValue(weapAtk, "Class") |
||
− | return iterator |
||
+ | table.insert(cats, ({ |
||
− | end |
||
+ | -- Principales |
||
+ | ["Canon à bras"] = "Armes/Canons à bras", |
||
+ | ["Arc"] = "Armes/Arcs", |
||
+ | ["Arbalète"] = "Armes/Arcs", |
||
+ | ["Fusil"] = "Armes/Fusils", |
||
+ | ["Fusil Sniper"] = "Armes/Fusils de Sniper", |
||
+ | ["Fusil à Pompe"] = "Armes/Fusils à Pompe", |
||
+ | ["Lance à énergie"] = "Armes/Lances à énergie", |
||
+ | ["Lanceur"] = "Armes/Lanceurs", |
||
+ | -- Secondaires |
||
+ | ["Doubles Pistolets"] = "Armes/Doubles Pistolets", |
||
+ | ["Fusil à Pompe à double canon"] = "Armes/Fusils à Pompe à double canon", |
||
+ | ["Fusil à Pompe court"] = "Armes/Fusils à Pompe courts", |
||
+ | ["Lancé"] = "Armes/Lancés", |
||
+ | ["Pistolet"] = "Armes/Pistolets", |
||
+ | ["Volume"] = "Armes/Volumes", |
||
+ | -- Mêlées |
||
+ | ["Arme d'hast"] = "Armes/Armes d'hast", |
||
+ | ["Bâton"] = "Armes/Bâtons", |
||
+ | ["Dague"] = "Armes/Dagues", |
||
+ | ["Doubles Dagues"] = "Armes/Doubles Dagues", |
||
+ | ["Doubles Nikanas"] = "Armes/Doubles Nikanas", |
||
+ | ["Doubles Épées"] = "Armes/Doubles Épées", |
||
+ | ["Faux"] = "Armes/Faux", |
||
+ | ["Faux Lourde"] = "Armes/Faux Lourdes", |
||
+ | ["Fouet"] = "Armes/Fouets", |
||
+ | ["Glaive"] = "Armes/Glaives", |
||
+ | ["Griffes"] = "Armes/Griffes", |
||
+ | ["Lame Lourde"] = "Armes/Lames Lourdes", |
||
+ | ["Lame et Fouet"] = "Armes/Lames et Fouets", |
||
+ | ["Machette"] = "Armes/Machettes", |
||
+ | ["Mains et Pieds"] = "Armes/Mains et Pieds", |
||
+ | ["Marteau"] = "Armes/Marteaux", |
||
+ | ["Nikana"] = "Armes/Nikanas", |
||
+ | ["Nikana à Deux Mains"] = "Armes/Nikanas à Deux Mains", |
||
+ | ["Nunchaku"] = "Armes/Nunchakus", |
||
+ | ["Pistolame"] = "Armes/Pistolames", |
||
+ | ["Poings"] = "Armes/Poings", |
||
+ | ["Rapière"] = "Armes/Rapières", |
||
+ | ["Scie d'Assaut"] = "Armes/Scies d'Assaut", |
||
+ | ["Tonfa"] = "Armes/Tonfas", |
||
+ | ["Épée"] = "Armes/Épées", |
||
+ | ["Épée et Bouclier"] = "Armes/Épées et Boucliers", |
||
+ | ["Éventail de guerre"] = "Armes/Éventails de guerre", |
||
+ | -- Spéciales |
||
+ | ["Arme Exaltée"] = "Armes/Exaltées", |
||
+ | ["Amplificateur"] = "Armes/Amplificateurs", |
||
+ | ["Arch-Fusil"] = "Armes/Arch-Fusils", |
||
+ | ["Arch-Fusil (Atmosphère)"] = "Armes/Arch-Fusils", |
||
+ | ["Arch-Mêlée"] = "Armes/Arch-Mêlées", |
||
+ | ["Pièce principale"] = "Armes/Railjack", |
||
+ | ["Tourelle"] = "Armes/Railjack", |
||
+ | ["Railjack Armament"] = "Armes/Railjack", |
||
+ | ["Unique"] = "Armes/Uniques", -- e.g Parazon/Robotiques/Molosses |
||
+ | -- Zaws |
||
+ | ["Zaw Rapière / Arme d'hast"] = "Armes/Zaws", |
||
+ | ["Zaw Machette / Marteau"] = "Armes/Zaws", |
||
+ | ["Zaw Faux / Bâton"] = "Armes/Zaws", |
||
+ | ["Zaw Nikana / Bâton"] = "Armes/Zaws", |
||
+ | ["Zaw Épée / Bâton"] = "Armes/Zaws", |
||
+ | ["Zaw Épée / Arme d'hast"] = "Armes/Zaws", |
||
+ | ["Zaw Machette / Arme d'hast"] = "Armes/Zaws", |
||
+ | ["Zaw Faux / Lame Lourde"] = "Armes/Zaws", |
||
+ | ["Zaw Machette / Arme d'hast"] = "Armes/Zaws", |
||
+ | ["Zaw Dague / Bâton"] = "Armes/Zaws", |
||
+ | ["Zaw Rapière / Arme d'hast"] = "Armes/Zaws", |
||
+ | -- Kitguns |
||
+ | ["Fusil Kitgun"] = "Armes/Kitguns", |
||
+ | ["Lanceur Kitgun"] = "Armes/Kitguns", |
||
+ | ["Pistolet Kitgun"] = "Armes/Kitguns", |
||
+ | ["Fusil à Pompe Kitgun"] = "Armes/Kitguns", |
||
+ | })[class] or "Armes/Inconnues") |
||
+ | -- Modular category ('Armes/Modulaires') |
||
− | local function getFamily(FamilyName) |
||
+ | if string.find(class, "^Zaw") or string.find(class, "Kitgun$") then |
||
− | local familyMembers = {} |
||
+ | table.insert(cats, "Armes/Modulaires") |
||
− | for i, Weapon in Shared.skpairs(WeaponData["Weapons"]) do |
||
+ | end |
||
− | if (Weapon.Family == FamilyName) then |
||
− | table.insert(familyMembers, Weapon) |
||
− | end |
||
− | end |
||
− | return familyMembers |
||
− | end |
||
+ | local family = p._getValue(weapAtk, "Family") |
||
− | -- Returns all melee weapons. |
||
+ | table.insert(cats, family) |
||
− | -- If weapType is not nil, only grab for a specific type |
||
+ | |||
− | -- For example, if weapType is "Nikana", only pull Nikanas |
||
− | local |
+ | local slot = p._getValue(weapAtk, "Slot") |
+ | table.insert(cats, ({ |
||
− | local weaps = {} |
||
+ | ["Principale"] = "Armes/Principales", -- Principale |
||
− | local weapClasses = {} |
||
+ | ["Secondaire"] = "Armes/Secondaires", -- Secondaire |
||
− | if (weapClass ~= nil) then |
||
+ | ["Mêlée"] = "Armes/Mêlées", -- Mêlée |
||
− | weapClasses = Shared.splitString(weapClass, ',') |
||
+ | -- Archwing |
||
− | end |
||
+ | ["Arch-Fusil"] = "Armes/Arch-Fusils", |
||
− | |||
+ | ["Arch-Fusil (Atmosphère)"] = "Armes/Arch-Fusils", |
||
− | for i, weap in Shared.skpairs(WeaponData["Weapons"]) do |
||
+ | ["Arch-Mêlée"] = "Armes/Arch-Mêlées", |
||
− | if ((weap.Ignore == nil or not weap.Ignore) and weap.Type ~= nil and |
||
+ | -- Railjack |
||
− | weap.Type == "Mêlée") then |
||
+ | ["Tourelle Railjack"] = "Armes/Railjacks", |
||
− | local classMatch = (weapClass == nil or |
||
+ | ["Pièce principale Railjack"] = "Armes/Railjacks", |
||
− | Shared.contains(weapClasses, weap.Class)) |
||
+ | -- |
||
− | local pvpMatch = (PvP == nil or |
||
+ | ["Amplificateur"] = "Armes/Amplificateurs", -- Amplificateurs |
||
− | (PvP and weap.Conclave ~= nil and weap.Conclave)) |
||
+ | ["Robotique"] = "Armes/Robotiques", -- Sentinelles |
||
− | if (classMatch and pvpMatch) then |
||
+ | ["Molosse"] = "Armes/Molosses", -- Molosses |
||
− | table.insert(weaps, weap) |
||
+ | ["Emplacement"] = "Armes/Emplacements", -- Rempart (only) |
||
− | end |
||
+ | ["Équipement"] = "Armes/Équipements", -- Ebisu / Lanzo / etc.. |
||
− | end |
||
+ | ["Nech-Mêlée"] = "Armes/Nech-Mêlées", -- Pugil |
||
− | end |
||
+ | ["Unique"] = "Armes/Uniques", -- e.g Parazon |
||
+ | ["Véhicule"] = "Armes/Véhicules", -- Dargyn |
||
+ | })[slot] or "Armes/Inconnues") |
||
+ | |||
+ | -- Fonctionnalité désactivée pour y insérer un tableau associatif juste après ce commentaire (Yazuh) |
||
+ | -- local trigger = p._getValue(weapAtk, "Trigger") |
||
+ | -- table.insert(cats, 'Armes ' .. trigger) |
||
+ | table.insert(cats, ({ |
||
− | return weaps |
||
+ | ["Activée"] = 'Armes/Tir à Activation', |
||
+ | ["Auto / Chargée"] = 'Armes/Chargée', |
||
+ | ["Automatique"] = 'Armes/Automatique', |
||
+ | ["Auto / Rafale"] = 'Armes/Tir en Rafale', |
||
+ | ["Cadence progressive"] = 'Armes/Automatique', |
||
+ | ["Rafale"] = 'Armes/Tir en Rafale', |
||
+ | ["Chargée"] = 'Armes/Chargée', |
||
+ | ["Duplex"] = 'Armes/Tir en Duplex', |
||
+ | ["Maintenue"] = 'Armes/Tir en continu', |
||
+ | ["Semi-auto"] = 'Armes/Semi-automatique', |
||
+ | })[trigger] or 'Armes') -- fix for melee weapon (no trigger) |
||
+ | |||
+ | local users = p._getValue(weapAtk, "Users") or {} |
||
+ | for _, user in ipairs(users) do table.insert(cats, user) end |
||
+ | |||
+ | -- Aucun besoin de cette fonctionnalité (by: Yazu) |
||
+ | -- local variant = p._getValue(weapAtk, "Variant") |
||
+ | -- table.insert(cats, variant) |
||
+ | |||
+ | local infAmmo = p._getValue(weapAtk, "AmmoMax") == math.huge |
||
+ | local accuracy = p._getValue(weapAtk, "Accuracy") |
||
+ | local pinpoint = accuracy ~= nil and accuracy >= 100 |
||
+ | local regens = p._getValue(weapAtk, "ReloadRate") > 0 |
||
+ | local silent = weapAtk.IsSilent -- automatically includes |
||
+ | local single = p._getValue(weapAtk, "Magazine") == 1 and not p._getValue(weapAtk, "IsMelee")--meh, delet? |
||
+ | local spools = p._getValue(weapAtk, "Spool") > 0 |
||
+ | local isAoE = p._getValue(weapAtk, "HasAoEAttack") |
||
+ | local isCodexSecret = p._getValue(weapAtk, "CodexSecret") |
||
+ | local isTradable = p._getValue(weapAtk, "Tradable") |
||
+ | local isInConclave = p._getValue(weapAtk, "Conclave") |
||
+ | |||
+ | -- Arbitrarily ordering misc categories |
||
+ | if infAmmo then table.insert(cats, 'Armes/Armes à munitions infinies') end |
||
+ | if pinpoint then table.insert(cats, 'Armes/Armes de précision') end |
||
+ | if regens then table.insert(cats, 'Armes/Armes à batterie') end |
||
+ | if silent then |
||
+ | table.insert(cats, 'Armes/Armes silencieuses') |
||
+ | else |
||
+ | table.insert(cats, 'Armes/Armes bruyantes') |
||
+ | end |
||
+ | if single then table.insert(cats, 'Armes/Armes à coup unique') end |
||
+ | if spools then table.insert(cats, 'Armes/Armes à bobine') end |
||
+ | if isAoE then table.insert(cats, 'Armes/Armes à zone d\'effet') end |
||
+ | if isCodexSecret then table.insert(cats, 'Armes/Secret du codex') end |
||
+ | if isTradable then |
||
+ | table.insert(cats, 'Armes/Armes échangeables') |
||
+ | else |
||
+ | table.insert(cats, 'Armes/Armes non échangeables') |
||
+ | end |
||
+ | if isInConclave then table.insert(cats, 'Armes/Disponibles au Conclave') end |
||
+ | |||
+ | return StatObject.cacheIn(weapAtk, 'Categories', cats) |
||
+ | end, function(s, cats) |
||
+ | local wikitextResult = { '' } -- Need to prepend a newline so first asterisk is rendered as a wikitext list |
||
+ | local formatStr = '*[[:Catégorie:%s|%s]][[Catégorie:%s]]' |
||
+ | for _, category in ipairs(cats) do |
||
+ | table.insert(wikitextResult, formatStr:format(category, category, category)) |
||
+ | end |
||
+ | return table.concat(wikitextResult, '\n') |
||
end |
end |
||
+ | }, |
||
− | |||
+ | SyndicateEffect = { '', function(s, v) |
||
− | -- As above, but for Conclave stats |
||
+ | return (v == '' or type(v) ~= 'string') and '' or Tooltip.icon(({ |
||
− | local function getConclaveMeleeWeapons(weapClass, PvP) |
||
+ | ['rouille'] = 'Voile Rouge', |
||
− | local weaps = {} |
||
+ | ['entropie'] = 'Céphalon Suda', |
||
− | local weapClasses = {} |
||
+ | ['justice'] = 'Méridien d\'Acier', |
||
− | if (weapClass ~= nil) then |
||
+ | ['pureté'] = 'Nouveau Loka', |
||
− | weapClasses = Shared.splitString(weapClass, ',') |
||
+ | ['séquence'] = 'La Séquence Perrin', |
||
− | end |
||
+ | ['vérité'] = 'Arbitres de Hexis', |
||
− | |||
+ | })[v:lower()] or 'Tenno', 'Factions') |
||
− | for i, weap in Shared.skpairs(ConclaveData["Weapons"]) do |
||
+ | ..' '..v |
||
− | if ((weap.Ignore == nil or not weap.Ignore) and weap.Type ~= nil and |
||
− | weap.Type == "Mêlée") 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 |
end |
||
+ | }, |
||
− | |||
+ | MinProgenitorBonus = function(weap) return weap.IsLichWeapon and statRead(weap, 'BaseDamage') * 0.25 or 0 end, |
||
− | -- Learning new things... Trying to allow sending in an arbitrary function |
||
+ | ProgenitorBonus = function(weap) return weap.IsLichWeapon and statRead(weap, 'BaseDamage') * 0.6 or 0 end, |
||
− | function p.getWeapons(validateFunction) |
||
+ | Class = '', |
||
− | local weaps = {} |
||
+ | SniperComboReset = { nil, '%.1f s' }, |
||
− | for i, weap in Shared.skpairs(WeaponData["Weapons"]) do |
||
+ | SniperComboMin = { nil, '%d shot(s)' }, |
||
− | if ((weap.Ignore == nil or not weap.Ignore) and validateFunction(weap)) then |
||
+ | Tradable = { function(weapAtk) |
||
− | table.insert(weaps, weap) |
||
+ | if type(weapAtk['Tradable'])=='number' then |
||
− | end |
||
+ | assert(weapAtk['Tradable']<=5, |
||
− | end |
||
+ | 'Tradable: Does not support tradeability enums beyond 5; please update [[Module:Weapons/data]] and [[Module:Weapons]] to support more tradeability edge cases') |
||
− | return weaps |
||
+ | return ({ |
||
+ | [0]=false, |
||
+ | [1]='Rang 0', |
||
+ | [2]='Parties', |
||
+ | [3]='Liches', |
||
+ | [4]='Parties pour fabrication', |
||
+ | [5]='Arme liée', |
||
+ | })[weapAtk['Tradable']] |
||
+ | end |
||
+ | return weapAtk['Tradable'] |
||
+ | end, function(s, tradable) |
||
+ | return ({ |
||
+ | [false] = 'Non-échangeable', |
||
+ | ['Unranked'] = 'Non classée sans Forma ou Catalyseur', |
||
+ | ['Parts'] = 'Pièces et/ou schéma uniquement', |
||
+ | ['Lich'] = 'Par le biais des échanges des [[Liche Kuva|Liches]].', |
||
+ | ['Built Parts'] = 'Uniquement des composants construits, et non des schémas', |
||
+ | ['Parent'] = 'Indirectement, livré avec le compagnon associé', |
||
+ | })[tradable] or 'Non-échangeable?' |
||
end |
end |
||
+ | }, |
||
− | |||
+ | SellPrice = { nil, function(self, sellPrice) |
||
− | -- Same as getWeapons, but for Conclave data |
||
+ | if sellPrice == nil then |
||
− | function p.getConclaveWeapons(validateFunction) |
||
+ | return 'Invendable' |
||
− | local weaps = {} |
||
+ | end |
||
− | for i, weap in Shared.skpairs(ConclaveData["Weapons"]) do |
||
+ | return Tooltip.icon('Crédits', 'Resources')..' '..Math.formatnum(sellPrice) |
||
− | if ((weap.Ignore == nil or not weap.Ignore) and validateFunction(weap)) then |
||
− | table.insert(weaps, weap) |
||
− | end |
||
− | end |
||
− | return weaps |
||
end |
end |
||
+ | }, |
||
− | |||
+ | DefaultUpgrades = { nil, function(self, upgradesArr) |
||
− | local function asMultiplier(val) |
||
+ | local result = {} |
||
− | if (val == nil) then return "1.0x" end |
||
+ | for _, modIndex in ipairs(upgradesArr or {}) do |
||
− | return Shared.round(val, 2, 1) .. "x" |
||
+ | table.insert(result, Tooltip.full(modIndex, 'Mods')) |
||
+ | end |
||
+ | return table.concat(result, '<br />') |
||
end |
end |
||
+ | }, |
||
− | |||
+ | Users = { nil, function(self, usersArr) |
||
− | local function HasTrait(Weapon, Trait) |
||
+ | local result = { '' } |
||
− | if (Trait == nil or Weapon.Traits == nil) then return false end |
||
+ | for _, user in ipairs(usersArr or {}) do |
||
− | |||
+ | table.insert(result, '*[['..user..']]') |
||
− | for i, theTrait in pairs(Weapon.Traits) do |
||
+ | end |
||
− | if (theTrait == Trait) then return true end |
||
+ | return table.concat(result, '\n') |
||
− | end |
||
− | |||
− | return false |
||
end |
end |
||
+ | }, |
||
− | |||
+ | Zoom = { unpacks('Zoom'), { sep = '<br />' } }, |
||
− | -- If Type is not nil, get damage weapon deals of that type |
||
+ | Slot = nil, |
||
− | -- If it deals no damage of that type, return 0 instead of nil |
||
+ | } |
||
− | -- It Type is nil, return total damage |
||
+ | -- Loops for adding to StatObject.default table |
||
− | local function GetDamage(Attack, Type, ByPellet) |
||
+ | -- Damage type getters: |
||
− | if (ByPellet == nil) then ByPellet = false end |
||
+ | -- <DamageType> = damage type value |
||
− | if (Attack == nil or Attack.Damage == nil) then return 0 end |
||
+ | -- <DamageType>Distribution = damage type distribution as a percentage |
||
− | |||
+ | -- PvP<DamageType> = damage type value with precise formatting for PvP purposes |
||
− | local pCount = 1 |
||
+ | for _, damageType in ipairs(iterationOrderArray) do |
||
− | if (ByPellet and Attack.PelletCount ~= nil) then |
||
+ | StatObject.default[damageType] = { |
||
− | pCount = Attack.PelletCount |
||
+ | function(weapAtk) return weapAtk['Damage'][damageType] or 0 end, |
||
− | end |
||
+ | function(self, value) return Tooltip.icon(damageType, 'DamageTypes')..' '..Math.formatnum(value) end |
||
− | if (Type == nil) then |
||
+ | } |
||
− | local total = 0 |
||
+ | -- Damage distribution as a percentage |
||
− | for i, d in Shared.skpairs(Attack.Damage) do total = total + d end |
||
+ | StatObject.default[damageType..'Distribution'] = { |
||
− | return total / pCount |
||
+ | function(weapAtk) return weapAtk['Damage'][damageType] / statRead(weapAtk, 'BaseDamage') end, |
||
− | else |
||
+ | function(self, value) return Tooltip.icon(damageType, 'DamageTypes')..' '..Math.percentage(value) end |
||
− | if (Type == "Physical") then |
||
+ | } |
||
− | local Impact = Attack.Damage["Impact"] ~= nil and |
||
+ | -- More precise damage values to 4 decimal places for PvP |
||
− | Attack.Damage["Impact"] or 0 |
||
+ | StatObject.default['PvP'..damageType] = { |
||
− | local Puncture = Attack.Damage["Perforation"] ~= nil and |
||
+ | function(weapAtk) return weapAtk['Damage'][damageType] or 0 end, |
||
− | Attack.Damage["Perforation"] or 0 |
||
+ | Tooltip.icon(damageType, 'DamageTypes')..' %.4f' |
||
− | local Slash = Attack.Damage["Tranchant"] ~= nil and |
||
+ | } |
||
− | Attack.Damage["Tranchant"] 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 |
end |
||
+ | -- TODO: Do not rely on localized name to determine a weapon's variant. Decouple localization from data |
||
− | -- Returns the damage string as it's formatted in a comparison row |
||
+ | --- Checks if a weapon is a variant or not. |
||
− | -- So instead of '0', returns '-', and appends the icon for an element if necessary |
||
+ | -- @function p._isVariant |
||
− | local function GetDamageString(Attack, Type, ByPellet) |
||
+ | -- @param {string} weaponName Weapon name |
||
− | if (ByPellet == nil) then ByPellet = false end |
||
+ | -- @returns {boolean} True if weapon is a variant, false otherwise |
||
− | if (Attack == nil or Attack.Damage == nil) then return "" end |
||
+ | -- @returns {string} Weapon's variant name or "Base" if weapon is not a variant |
||
− | |||
+ | -- @returns {string} Weapon name, same as weaponName |
||
− | local pCount = 1 |
||
+ | function p._isVariant(weaponName) |
||
− | if (ByPellet and Attack.PelletCount ~= nil) then |
||
+ | for i, var in pairs(VARIANT_LIST) do |
||
− | pCount = Attack.PelletCount |
||
+ | if (var ~= "Dex" or weaponName ~= "Dex Pixia") then |
||
− | end |
||
− | + | if string.find(weaponName, var) then |
|
+ | return true, var, (string.gsub(weaponName, " ?"..var.." ?-?", "")) |
||
− | if (not hasMultipleTypes(Attack)) then |
||
+ | end |
||
− | for key, val in pairs(Attack.Damage) do |
||
+ | end |
||
− | if (val > 0) then |
||
+ | end |
||
− | return Icon._Proc(key) .. " " .. |
||
+ | return false, "Variante de base", weaponName |
||
− | 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 |
end |
||
+ | --- Builds the full name of a weapon's variant. Does not check if it exists or not. |
||
− | local function GetDamageBias(Attack, IncludeSingle) |
||
+ | -- @function p._buildName |
||
− | if (IncludeSingle == nil) then IncludeSingle = false end |
||
+ | -- @param {string} baseName Weapon's base name (e.g. "Braton") |
||
− | |||
+ | -- @param[opt] {string} variant Variant name (e.g. "Vandal"); if nil, returns base weapon name instead |
||
− | if (Attack.Damage ~= nil and Shared.tableCount(Attack.Damage) > 0) then |
||
+ | -- @returns {string} Weapon's variant name (e.g. "Braton Vandal") |
||
− | local total = 0 |
||
+ | function p._buildName(baseName, variant) |
||
− | local bestDmg = 0 |
||
+ | if not variant or variant == 'Base' or variant == '' then |
||
− | local bestElement = nil |
||
+ | return baseName |
||
− | local count = 0 |
||
+ | end |
||
− | for Element, Dmg in pairs(Attack.Damage) do |
||
+ | return (({ |
||
− | if (Dmg > bestDmg) then |
||
+ | -- Prime Laser Rifle is an edge case for Prime naming scheme (at least in EN localization) |
||
− | bestDmg = Dmg |
||
+ | Prime = baseName ~= 'Fusil Laser' and '%b %v', |
||
− | bestElement = Element |
||
+ | Vandal = '%b %v', |
||
− | end |
||
+ | Wraith = '%b %v', |
||
− | total = total + Dmg |
||
+ | MK1 = '%v-%b', |
||
− | if (Dmg > 0) then count = count + 1 end |
||
+ | })[variant] or '%v %b'):gsub('%%v', variant):gsub('%%b', baseName) |
||
− | 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 |
end |
||
+ | --- Returns a specific weapon table entry from <code>/data</code> or <code>/Conclave/data</code>. |
||
− | -- If the attack has at least two damage types, |
||
+ | -- @function p._getWeapon |
||
− | -- Returns something like "58.3% Slash" |
||
+ | -- @param {string} weaponName Weapon name |
||
− | -- If it doesn't, returns nil |
||
+ | -- @param[opt] {boolean} pvp If true, gets PvP stats of weapon instead, false otherwise; defaults to false |
||
− | local function GetDamageBiasString(Attack, HideType, ShowText, IncludeSingle, |
||
+ | -- @returns {table} Weapon table |
||
− | Color) |
||
+ | function p._getWeapon(weaponName, pvp) |
||
− | if (HideType == nil) then HideType = false end |
||
+ | weaponName = mw.text.decode(weaponName) |
||
− | if (ShowText == nil) then ShowText = "" end |
||
+ | return (pvp and ConclaveData or WeaponData)[weaponName] or |
||
− | if (IncludeSingle == nil) then IncludeSingle = false end |
||
+ | error('p._getWeapon(weaponName, pvp): "'..weaponName.. |
||
− | |||
+ | '" does not exist in '..(pvp and '[[Module:Weapons/Conclave/data]]' or '[[Module:Weapons/data]]')) |
||
− | local bestPercent, bestElement = GetDamageBias(Attack, IncludeSingle) |
||
− | if (bestPercent ~= nil) then |
||
− | local result = Shared.asPercent(bestPercent, 0) |
||
− | if (not HideType) then |
||
− | result = Icon._Proc(bestElement, ShowText, Color) .. " " .. result |
||
− | end |
||
− | return result |
||
− | else |
||
− | return nil |
||
− | end |
||
end |
end |
||
+ | --- Gets the raw value of a certain statistic of a weapon. |
||
− | function p.GetPolarityString(Weapon) |
||
+ | -- @function p._getValue |
||
− | |||
+ | -- @param {table} Weapon Weapon table |
||
− | local ret = Icon.PolList(Weapon.Polarities) |
||
+ | -- @param {string} key Name of key |
||
− | if (ret ~= "Aucune") then |
||
+ | -- @param[opt] {string} attack Name of attack to search through; defaults to 'Attack1' or what '_TooltipAttackDisplay' is set to |
||
− | -- Adding Exceptions |
||
+ | -- @returns {string, number} Value of statistic |
||
− | if (Weapon.Name == "Lame Exaltée") then |
||
+ | function p._getValue(weap, key, atk)--, formatted) |
||
− | ret = ret .. "(Vanilla/Prime)<br/>" .. Icon._Pol("Umbra") .. |
||
+ | -- return (formatted and statFormat or statRead)(weap, atk, key) |
||
− | Icon._Pol("Umbra") .. "(Umbra)" |
||
+ | return p._statRead(weap, atk, key) |
||
− | end |
||
− | end |
||
− | |||
− | return ret |
||
end |
end |
||
+ | --- Gets the formatted value of a certain statistic of a weapon to be displayed |
||
− | local function getWeaponStanceList(Weapon) |
||
+ | -- the wiki. |
||
− | if (Weapon == nil or Weapon.Type ~= "Mêlée") then return nil end |
||
+ | -- @function p._getFormattedValue |
||
− | |||
+ | -- @param {table} Weapon Weapon table |
||
− | local stances = Mod.getStances(Weapon.Class, Weapon.Conclave, Weapon.Name) |
||
+ | -- @param {string} keyName Name of key |
||
− | |||
+ | -- @param[opt] {string} attackName Name of attack to search through; defaults to 'Attack1' |
||
− | local result = "" |
||
+ | -- @returns {string} Value of statistic |
||
− | |||
+ | function p._getFormattedValue(weap, key, atk) |
||
− | for i, stance in pairs(stances) do |
||
+ | -- return p._getValue(Weapon, keyName, attackName, true) |
||
− | if (string.len(result) > 0) then result = result .. "<br/>" end |
||
+ | return p._statFormat(weap, atk, key) |
||
− | |||
− | local polarity = '' |
||
− | local link = '' |
||
− | |||
− | if Weapon.Class ~= "Arme Exaltée" or Weapon.Name == "Serres de Garuda" then |
||
− | result = result .. Tooltip._tooltipText(stance.Name, 'Mod') |
||
− | end |
||
− | |||
− | result = result .. polarity |
||
− | -- If this is a PvP Stance, add the disclaimer |
||
− | local stancePvP = Mod._getValue(stance.Name, "PVP") |
||
− | if (stancePvP) then result = result .. " (PvP)" end |
||
− | end |
||
− | |||
− | return result |
||
end |
end |
||
+ | --- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair. |
||
− | local function getAttackValue(Weapon, Attack, ValName, giveDefault, asString, |
||
+ | -- @function p._statReader |
||
− | forTable) |
||
+ | -- @param {table} weap Weapon entry |
||
− | if (giveDefault == nil) then giveDefault = false end |
||
+ | -- @param {number|table} atk Attacks table index or Attack entry |
||
− | if (asString == nil) then asString = false end |
||
+ | -- @return {function} Getter function |
||
− | if (forTable == nil) then forTable = false end |
||
+ | function p._statReader(weap, atk) |
||
− | if (Attack == nil) then |
||
+ | return function(...) return p._statRead(weap, atk, ...) end |
||
− | if (asString) then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | end |
||
− | local 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 .. " mun. par tir" |
||
− | else |
||
− | return Attack.AmmoCost |
||
− | end |
||
− | elseif (giveDefault) then |
||
− | return 1 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "BLOCKANGLE") then |
||
− | if (Weapon.BlockAngle ~= nil) then |
||
− | if (asString) then |
||
− | return Weapon.BlockAngle .. "°" |
||
− | else |
||
− | return Weapon.BlockAngle |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "BURSTCOUNT") then |
||
− | if (Attack.BurstCount ~= nil) then |
||
− | if (asString) then |
||
− | local result = Attack.BurstCount .. " balles" |
||
− | local dmg = GetDamage(Attack) * Attack.BurstCount |
||
− | return result .. " (" .. Shared.round(dmg, 2, 1) .. |
||
− | " dégâts totaux)" |
||
− | 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 Shared.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 Shared.asPercent(normAtt.CritChance) |
||
− | else |
||
− | return normAtt.CritChance |
||
− | end |
||
− | end |
||
− | end |
||
− | if giveDefault then |
||
− | if (asString) then |
||
− | return Shared.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) <= 4) then |
||
− | if (GetDamageBiasString(Attack, nil, nil, giveDefault) ~= nil) then |
||
− | return GetDamageBiasString(Attack, nil, nil, giveDefault) |
||
− | else |
||
− | return "" |
||
− | end |
||
− | else |
||
− | if (asString or giveDefault) 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 = "Dégâts max. jusqu'à " .. |
||
− | Shared.round(Attack.Falloff.StartRange, 2, 1) .. |
||
− | " m" |
||
− | falloffText = falloffText .. "<br/>Dégâts min. à partir de " .. |
||
− | Shared.round(Attack.Falloff.EndRange, 2, 1) .. |
||
− | " m" |
||
− | if (Attack.Falloff.Reduction ~= nil) then |
||
− | falloffText = falloffText .. "<br/>" .. |
||
− | Shared.asPercent(Attack.Falloff.Reduction) .. |
||
− | " réduction max." |
||
− | 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 ~= "Mêlée" 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(" balle<s>/s", 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 == "FOLLOWTHROUGH") then |
||
− | if (Weapon.FollowThrough ~= nil) then |
||
− | if (asString) then |
||
− | return Shared.asPercent(Weapon.FollowThrough, 0) |
||
− | else |
||
− | return Weapon.FollowThrough |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEADSHOTMULTIPLIER") then |
||
− | -- search in current attack, then normal, and finally fall back on base weapon value if for some reason that exists |
||
− | if (Attack.HeadshotMultiplier ~= nil) then |
||
− | if (asString) then |
||
− | return asMultiplier(Attack.HeadshotMultiplier) |
||
− | else |
||
− | return Attack.HeadshotMultiplier |
||
− | end |
||
− | end |
||
− | if (hasAttack(Weapon, "Normal")) then |
||
− | local normAtt = getAttack(Weapon, "Normal") |
||
− | if (normAtt.HeadshotMultiplier ~= nil) then |
||
− | if (asString) then |
||
− | return asMultiplier(normAtt.HeadshotMultiplier) |
||
− | else |
||
− | return normAtt.HeadshotMultiplier |
||
− | end |
||
− | end |
||
− | end |
||
− | if (Weapon.HeadshotMultiplier ~= nil) then |
||
− | if (asString) then |
||
− | return asMultiplier(Weapon.HeadshotMultiplier) |
||
− | else |
||
− | return Weapon.HeadshotMultiplier |
||
− | end |
||
− | end |
||
− | if giveDefault then |
||
− | if (Weapon.Type ~= nil) then |
||
− | -- Setting multiplier based on default for each weapon type |
||
− | if (Weapon.Type == "Secondaire") then |
||
− | if (Weapon.Class == "Shotgun Sidearm") then |
||
− | return '1.2x' |
||
− | elseif (Weapon.Class == "Arbalète" or Weapon.Class == |
||
− | "Thrown") then |
||
− | return '1.5x' |
||
− | else |
||
− | if (Weapon.Trigger == 'Auto') then |
||
− | return '1.2x' |
||
− | else |
||
− | return '1.5x' |
||
− | end |
||
− | end |
||
− | elseif (Weapon.Type == "Principale") then |
||
− | if (Weapon.Class == "Fusil à Pompe") then |
||
− | return "1.2x" |
||
− | elseif (Weapon.Class == "Arc") then |
||
− | return "2.0x" |
||
− | elseif (Weapon.Class == "Fusil Sniper") then |
||
− | return "1.4x" |
||
− | elseif (Weapon.Class == "Launcher") then |
||
− | return "1.0x" |
||
− | else |
||
− | if (Weapon.Trigger == "Auto") then |
||
− | return '1.2x' |
||
− | else |
||
− | return '1.5x' |
||
− | end |
||
− | end |
||
− | end |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "MELEECOMBODUR") then |
||
− | if (Weapon.MeleeComboDur ~= nil) then |
||
− | if (asString) then |
||
− | return Weapon.MeleeComboDur .. " s" |
||
− | else |
||
− | return Weapon.MeleeComboDur |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 5.0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "MELEERANGE") then |
||
− | if (Weapon.MeleeRange ~= nil) then |
||
− | if (asString) then |
||
− | return Weapon.MeleeRange .. " m" |
||
− | else |
||
− | return Weapon.MeleeRange |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 1 |
||
− | 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 .. " par " .. string.lower(Attack.PelletName) |
||
− | else |
||
− | return result .. " par balle" |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "PELLETNAME") then |
||
− | if (Attack.PelletCount ~= nil) then |
||
− | if (Attack.PelletName ~= nil) then |
||
− | return Attack.PelletName |
||
− | else |
||
− | return "Balle" |
||
− | 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 .. " dégâts par " .. |
||
− | string.lower(Attack.PelletName) .. ")" |
||
− | else |
||
− | return result .. " dégâts par balle)" |
||
− | 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 .. " balles" |
||
− | 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 Shared.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 Shared.asPercent(normAtt.StatusChance) |
||
− | else |
||
− | return normAtt.StatusChance |
||
− | end |
||
− | end |
||
− | end |
||
− | if giveDefault then |
||
− | if (asString) then |
||
− | return Shared.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 == nil) then |
||
− | if (Weapon.Trigger ~= nil) then return Weapon.Trigger end |
||
− | else |
||
− | return Attack.Trigger |
||
− | end |
||
− | |||
− | if giveDefault then |
||
− | return "Inconnu" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | else |
||
− | return "ERREUR : No such value " .. ValName |
||
− | end |
||
end |
end |
||
+ | --- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair. |
||
− | local function getValue(Weapon, ValName, giveDefault, asString, forTable) |
||
+ | -- @function p._statFormatter |
||
− | if (giveDefault == nil) then giveDefault = false end |
||
+ | -- @param {table} weap Weapon entry |
||
− | if (asString == nil) then asString = false end |
||
+ | -- @param {number|table} atk Attacks table index or Attack entry |
||
− | if (forTable == nil) then forTable = false end |
||
+ | -- @return {function} Getter function |
||
− | |||
+ | function p._statFormatter(weap, atk) |
||
− | if (type(ValName) == "table") then |
||
+ | return function(...) return p._statFormat(weap, atk, ...) end |
||
− | 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) |
||
− | elseif (VName1 == "SLAM" or VName1 == "SLAMATTACK") then |
||
− | return getAttackValue(Weapon, getAttack(Weapon, "MeleeSlam"), |
||
− | VName2, giveDefault, asString, forTable) |
||
− | elseif (VName1 == "HEAVY" or VName1 == "HEAVYATTACK") then |
||
− | return getAttackValue(Weapon, getAttack(Weapon, "MeleeHeavy"), |
||
− | 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 |
||
− | if (string.find(Weapon.Name, "Atmosphère") ~= nil) then |
||
− | return "[[" .. |
||
− | string.gsub(Weapon.Name, "%s%(Atmosphère%)", "") .. |
||
− | "|" .. string.gsub(Weapon.Name, "osphère", "") .. |
||
− | "]]" |
||
− | else |
||
− | return "[[" .. Weapon.Name .. "]]" |
||
− | end |
||
− | 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 == "Secondaire") then |
||
− | return "Pistolet" |
||
− | elseif (Weapon.Type == "Principale") then |
||
− | if (Weapon.Class == nil or Weapon.Class == "Fusil") then |
||
− | return "Fusil" |
||
− | elseif (Weapon.Class == "Fusil à Pompe") then |
||
− | return "Fusil à Pompe" |
||
− | elseif (Weapon.Class == "Fusil de Sniper" or Weapon.Class == |
||
− | "Arc" or Weapon.Class == "Launcher") then |
||
− | return "Sniper/Arc" |
||
− | end |
||
− | end |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "AUGMENT") then |
||
− | local augments = Mod.getWeaponAugments(Weapon) |
||
− | local ret = {} |
||
− | for i, Aug in pairs(augments) do |
||
− | if (Aug.PvP) then |
||
− | table.insert(ret, |
||
− | Tooltip._tooltipText(Aug.Name, 'Mod') .. ' (PvP)') |
||
− | else |
||
− | table.insert(ret, Tooltip._tooltipText(Aug.Name, 'Mod')) |
||
− | end |
||
− | end |
||
− | return table.concat(ret, '\n') |
||
− | elseif (ValName == "BLOCKRESIST") then |
||
− | if (Weapon.Class ~= nil) then |
||
− | if (Weapon.Type == "Mêlée") then |
||
− | if (Weapon.BlockResist ~= nil) then |
||
− | if (asString) then |
||
− | return Shared.asPercent(Weapon.BlockResist) |
||
− | else |
||
− | return Weapon.BlockResist |
||
− | end |
||
− | elseif (Weapon.Class == "Claws" or Weapon.Class == "Dague" or |
||
− | Weapon.Class == "Doubles Dagues" 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 == |
||
− | "Doubles Épées" or Weapon.Class == "Fist" or Weapon.Class == |
||
− | "Gunblade" or Weapon.Class == "Bâton" or Weapon.Class == |
||
− | "Épée") then |
||
− | if (asString) then |
||
− | return "60%" |
||
− | else |
||
− | return .6 |
||
− | end |
||
− | elseif (Weapon.Class == "Marteau" or Weapon.Class == |
||
− | "Lame Lourde" or Weapon.Class == "Machette" or Weapon.Class == |
||
− | "Nikana" or Weapon.Class == "Polearm" or Weapon.Class == |
||
− | "Faux" or Weapon.Class == "Épée et Bouclier") 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 == "Mêlée") 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 |
||
− | return "[[:Category:" .. Weapon.Class .. "|" .. Weapon.Class .. "]]" |
||
− | 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-Mêlée" or Weapon.Type == |
||
− | "Emplacement") then return nil end |
||
− | |||
− | if (Weapon.Disposition ~= nil) then |
||
− | if (asString) then |
||
− | return Icon._Dis(Weapon.Disposition) .. |
||
− | '<div style="display:inline; position:relative; bottom:2px">(' .. |
||
− | Weapon.Disposition .. ')</div>' |
||
− | else |
||
− | return Weapon.Disposition |
||
− | end |
||
− | elseif giveDefault then |
||
− | if (asString) then |
||
− | return "Inconnu" |
||
− | else |
||
− | return 0 |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "DISPOSITION5") then |
||
− | if (Weapon.Type ~= nil and |
||
− | (Weapon.Type == "Arch-Fusil" or Weapon.Type == "Arch-Mêlée") or |
||
− | Weapon.Type == "Emplacement") then return nil end |
||
− | |||
− | if (Weapon.Disposition ~= nil) then |
||
− | if (Weapon.Disposition < 0.7) then |
||
− | return 1 |
||
− | elseif (Weapon.Disposition < 0.9) then |
||
− | return 2 |
||
− | elseif (Weapon.Disposition <= 1.1) then |
||
− | return 3 |
||
− | elseif (Weapon.Disposition <= 1.3) then |
||
− | return 4 |
||
− | else |
||
− | return 5 |
||
− | end |
||
− | elseif giveDefault then |
||
− | if (asString) then |
||
− | return "Inconnu" |
||
− | 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 .. "<br/>" |
||
− | end |
||
− | FamilyString = |
||
− | FamilyString .. |
||
− | Tooltip._tooltipText(Weap.Name, 'Weapon') |
||
− | end |
||
− | end |
||
− | return FamilyString |
||
− | end |
||
− | else |
||
− | return Weapon.Family |
||
− | end |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "EXILUSPOLARITY") then |
||
− | if (Weapon.ExilusPolarity ~= nil) then |
||
− | return Icon._Pol(Weapon.ExilusPolarity) |
||
− | 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 == "HEAVYATTACK") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.Damage ~= nil) then |
||
− | local heavyDamage = Weapon.MeleeHeavy.Damage |
||
− | if (asString) then |
||
− | if (Weapon.MeleeHeavy.Element ~= nil) then |
||
− | return Icon._Proc(Weapon.MeleeHeavy.Element) .. " " .. |
||
− | Shared.round(heavyDamage, 2, 1) |
||
− | else |
||
− | return Shared.round(heavyDamage, 2, 1) |
||
− | end |
||
− | else |
||
− | return heavyDamage |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYELEMENT") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.Element ~= nil) then |
||
− | return Weapon.MeleeHeavy.Element |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "WINDUP") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.WindUp ~= nil) then |
||
− | local windUp = Weapon.MeleeHeavy.WindUp |
||
− | if (asString) then |
||
− | return windUp .. " s" |
||
− | else |
||
− | return windUp |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYSLAMATTACK") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.SlamDamage ~= nil) then |
||
− | local heavySlamDamage = Weapon.MeleeHeavy.SlamDamage |
||
− | if (asString) then |
||
− | if (Weapon.MeleeHeavy.SlamElement ~= nil) then |
||
− | return Icon._Proc(Weapon.MeleeHeavy.SlamElement) .. " " .. |
||
− | Shared.round(heavySlamDamage, 2, 1) |
||
− | else |
||
− | return Shared.round(heavySlamDamage, 2, 1) |
||
− | end |
||
− | else |
||
− | return heavySlamDamage |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYSLAMELEMENT") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.SlamElement ~= nil) then |
||
− | return Weapon.MeleeHeavy.SlamElement |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYRADIALDMG") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.SlamRadialDamage ~= |
||
− | nil) then |
||
− | local damage = Weapon.MeleeHeavy.SlamRadialDamage |
||
− | if (asString) then |
||
− | if (Weapon.MeleeHeavy.SlamRadialElement ~= nil) then |
||
− | return Icon._Proc(Weapon.MeleeHeavy.SlamRadialElement) .. |
||
− | " " .. Shared.round(damage, 2, 1) |
||
− | else |
||
− | return Shared.round(damage, 2, 1) |
||
− | end |
||
− | else |
||
− | return damage |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYRADIALELEMENT") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.SlamRadialElement ~= |
||
− | nil) then |
||
− | return Weapon.MeleeHeavy.SlamRadialElement |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "HEAVYSLAMRADIUS") then |
||
− | if (Weapon.MeleeHeavy ~= nil and Weapon.MeleeHeavy.SlamRadius ~= nil) then |
||
− | local radius = Weapon.MeleeHeavy.SlamRadius |
||
− | if (asString) then |
||
− | return Shared.round(radius, 2, 1) .. " m" |
||
− | else |
||
− | return radius |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | 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(" balle<s> par chargeur", |
||
− | Weapon.Magazine) |
||
− | end |
||
− | else |
||
− | return Weapon.Magazine |
||
− | end |
||
− | elseif giveDefault then |
||
− | if (asString) then |
||
− | return "0 balles par chargeur" |
||
− | 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 == "Secondaire") then |
||
− | returnVal = 210 |
||
− | elseif (Weapon.Type == "Principale") then |
||
− | if (Weapon.Class == nil or Weapon.Class == "Fusil") then |
||
− | returnVal = 540 |
||
− | elseif (Weapon.Class == "Fusil à Pompe") then |
||
− | returnVal = 120 |
||
− | elseif (Weapon.Class == "Arc" or Weapon.Class == |
||
− | "Fusil Sniper") then |
||
− | returnVal = 72 |
||
− | end |
||
− | end |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | if (asString) then |
||
− | if (returnVal > 0) then |
||
− | return returnVal .. " munitions" |
||
− | 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 ~= "Mêlée" and Weapon.Type ~= |
||
− | "Arch-Melee") then |
||
− | if (Weapon.Class ~= nil and |
||
− | (Weapon.Class == "Arc" or Weapon.Class == "Thrown")) then |
||
− | return "Silencieux" |
||
− | else |
||
− | return "Bruyant" |
||
− | 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 "Aucune" |
||
− | 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 p. s." |
||
− | 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 == "SLAMATTACK") then |
||
− | if (Weapon.MeleeSlam ~= nil and Weapon.MeleeSlam.Damage ~= nil) then |
||
− | local slamDamage = Weapon.MeleeSlam.Damage |
||
− | if (asString) then |
||
− | if (Weapon.MeleeSlam.Element ~= nil) then |
||
− | return Icon._Proc(Weapon.MeleeSlam.Element) .. " " .. |
||
− | Shared.round(slamDamage, 2, 1) |
||
− | else |
||
− | return Shared.round(slamDamage, 2, 1) |
||
− | end |
||
− | else |
||
− | return Weapon.MeleeSlam |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "SLAMELEMENT") then |
||
− | if (Weapon.MeleeSlam ~= nil and Weapon.MeleeSlam.Element ~= nil) then |
||
− | return Weapon.MeleeSlam.Element |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "SLAMRADIALDMG") then |
||
− | if (Weapon.MeleeSlam ~= nil and Weapon.MeleeSlam.RadialDamage ~= nil) then |
||
− | local radialDamage = Weapon.MeleeSlam.RadialDamage |
||
− | if (asString) then |
||
− | local radialElement = Weapon.MeleeSlam.RadialElement |
||
− | if (radialElement ~= nil) then |
||
− | return Icon._Proc(radialElement) .. " " .. |
||
− | Shared.round(radialDamage, 2, 1) |
||
− | else |
||
− | return Shared.round(radialDamage, 2, 1) |
||
− | end |
||
− | else |
||
− | return radialDamage |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "SLAMRADIALELEMENT") then |
||
− | if (Weapon.MeleeSlam ~= nil and Weapon.MeleeSlam.Element ~= nil) then |
||
− | return Weapon.MeleeSlam.Element |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "SLAMRADIUS") then |
||
− | if (Weapon.MeleeSlam ~= nil and Weapon.MeleeSlam.Radius ~= nil) then |
||
− | local radius = Weapon.MeleeSlam.Radius |
||
− | if (asString) then |
||
− | return Shared.round(radius, 2, 1) .. " m" |
||
− | else |
||
− | return radius |
||
− | 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 .. " tirs" |
||
− | 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 "Aucune" |
||
− | 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 == "Rafale") 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, "Secondaire") and returnVal == 0) then |
||
− | local secAtt = getAttack(Weapon, "Secondaire") |
||
− | if (secAtt.CritChance ~= nil) then |
||
− | returnVal = secAtt.CritChance |
||
− | Attack = secAtt |
||
− | end |
||
− | end |
||
− | if (asString and returnVal ~= 0) then |
||
− | return Shared.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, "Secondaire") and returnVal == 0) then |
||
− | local secAtt = getAttack(Weapon, "Secondaire") |
||
− | 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 ~= "Mêlée" 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(" balle<s>/s", 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, "Secondaire") and returnVal == 0) then |
||
− | local secAtt = getAttack(Weapon, "Secondaire") |
||
− | if (secAtt.StatusChance ~= nil) then |
||
− | returnVal = secAtt.StatusChance |
||
− | Attack = secAtt |
||
− | end |
||
− | end |
||
− | if (asString and returnVal ~= 0) then |
||
− | return Shared.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 .. '<br/>' |
||
− | end |
||
− | result = result .. str |
||
− | end |
||
− | return result |
||
− | else |
||
− | return Weapon.Users |
||
− | end |
||
− | elseif giveDefault then |
||
− | return {} |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "WALLATTACK") then |
||
− | if (Weapon.WallAttack ~= nil) then |
||
− | if (asString) then |
||
− | if (Weapon.WallElement ~= nil) then |
||
− | return Icon._Proc(Weapon.WallElement) .. " " .. |
||
− | Shared.round(Weapon.WallAttack, 2, 1) |
||
− | else |
||
− | return Shared.round(Weapon.WallAttack, 2, 1) |
||
− | end |
||
− | else |
||
− | return Weapon.WallAttack |
||
− | end |
||
− | elseif giveDefault then |
||
− | return 0 |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "WALLELEMENT") then |
||
− | if (Weapon.WallElement ~= nil) then |
||
− | return Weapon.WallElement |
||
− | elseif giveDefault then |
||
− | return "" |
||
− | else |
||
− | return nil |
||
− | end |
||
− | elseif (ValName == "ZOOM") then |
||
− | if (Weapon.Zoom ~= nil) then |
||
− | if (asString) then |
||
− | local result = "" |
||
− | for i, str in pairs(Weapon.Zoom) do |
||
− | if (i > 1) then |
||
− | result = result .. '<br/>' |
||
− | end |
||
− | result = result .. str |
||
− | end |
||
− | return result |
||
− | else |
||
− | return Weapon.Zoom |
||
− | end |
||
− | else |
||
− | return nil |
||
− | end |
||
− | 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 |
end |
||
+ | --- Returns a subset of <code>/data</code> or <code>/Conclave/data</code> based on a validation function. |
||
− | function p.getValue(frame) |
||
+ | -- @function p._getWeapons |
||
− | local WeapName = frame.args[1] |
||
+ | -- @param {function} validateFunction Function that filters out a weapon by taking in a Weapon table argument |
||
− | local ValName1 = frame.args[2] |
||
+ | -- @param[opt] {string} source Name of weapon entry to use |
||
− | local ValName2 = frame.args[3] |
||
+ | -- @param[opt] {boolean} ignoreIgnore If true, ignores the _IgnoreEntry flag, false otherwise; defaults to false |
||
− | local AsString = frame.args["Raw"] == nil or frame.args["Raw"] == '' |
||
+ | -- @param[opt] {function} sortFunc Custom comparison function; false -> no sorting; defaults to sorting in ascending order by weapon name |
||
− | |||
+ | -- @returns {table} Table of weapon table entries as seen in <code>/data</code> |
||
− | if (WeapName == nil) then |
||
+ | function p._getWeapons(validateFunction, source, opts) |
||
− | return "" |
||
+ | opts=opts or {} |
||
− | elseif (ValName1 == nil) then |
||
+ | local ignoreIgnore, sortFunc, pvp = opts.ignoreIgnore, opts.sortFunc, opts.pvp |
||
− | return "ERREUR : Pas de valeur spécifiée" |
||
+ | validateFunction = validateFunction or function() return true end |
||
− | end |
||
+ | local data = pvp and ConclaveData or WeaponData |
||
− | |||
+ | if source then |
||
− | local theWeap = p.getWeapon(WeapName) |
||
+ | data = data[source] |
||
− | if (theWeap == nil) then return "" end |
||
+ | 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 |
||
+ | local weaps = {} |
||
− | return getValue(theWeap, vName, useDefault, AsString) |
||
+ | for _, weap in pairs(data) do |
||
+ | if (ignoreIgnore or not weap['_IgnoreEntry']) and validateFunction(weap) then |
||
+ | table.insert(weaps, weap) |
||
+ | end |
||
+ | end |
||
+ | if sortFunc ~= false then |
||
+ | table.sort(weaps, sortFunc or function(a, b) return a.Name < b.Name end) |
||
+ | end |
||
+ | return weaps |
||
end |
end |
||
+ | --- Returns all melee weapons. If weapType is not nil, only grab for a specific type |
||
− | function p.getConclaveValue(frame) |
||
+ | -- For example, if weapType is "Nikana", only pull Nikanas. |
||
− | local WeapName = frame.args[1] |
||
+ | -- @function p._getMeleeWeapons |
||
− | local ValName1 = frame.args[2] |
||
+ | -- @param[opt] {boolean} weapType |
||
− | local ValName2 = frame.args[3] |
||
+ | -- @param[opt] {boolean} pvp If true, only gets melee weapons available in Conclave, false otherwise; defaults to false |
||
− | if (WeapName == nil) then |
||
+ | -- @returns {table} An array of melee weapon table entries as seen in <code>/data</code> |
||
− | return "" |
||
+ | function p._getMeleeWeapons(weapType,pvp) |
||
− | elseif (ValName1 == nil) then |
||
+ | return p._getWeapons(weapType and function(weap) return weap.Class==weapType end, 'mêlée',{['pvp']=pvp==true}) |
||
− | 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 |
end |
||
+ | --- Main frame invokable function to access any raw/computed attribute/column/key of a weapon entry. |
||
− | local function buildInfoboxRow(Label, Text, Collapse, Digits, Addon) |
||
+ | -- See default table in M:Weapons to see all valid computed attributes. |
||
− | local result = "" |
||
+ | -- @function p.getValue |
||
− | |||
+ | -- @param {string} weap Weapon name in EN locale |
||
− | if (Collapse == nil) then |
||
+ | -- @param {number} atk Attacks table index |
||
− | Collapse = false |
||
+ | -- @param {string} k Key name |
||
− | elseif (Collapse == 1) then |
||
+ | -- @return Raw or computed value associated with k key |
||
− | Collapse = true |
||
+ | function p.getValue(frame) |
||
− | end |
||
+ | -- table.unpack doesn't work on the frame object which is why this is anonymous function is needed |
||
− | if (Text ~= nil) then |
||
+ | local weap, key, atk = (function(t) return t[1], t[2], t[3] end)(frame.args) |
||
− | result = '<div style="margin-left:-3px;" ' |
||
+ | weap = p._getWeapon(weap) |
||
− | if (Collapse) then |
||
+ | return p._getValue(weap, key, atk) |
||
− | result = result .. 'class="Infobox_Collapsible"' |
||
− | end |
||
− | result = result .. '>' |
||
− | result = result .. '\n{| style="width:100%;"' |
||
− | result = result .. '\n|-' |
||
− | result = result .. |
||
− | '\n| class="left" | <span style="white-space:nowrap;">' |
||
− | result = result .. "'''" .. Label .. "'''" |
||
− | result = result .. '</span>' |
||
− | result = result .. '\n| class="right" | ' |
||
− | if (Digits == nil) then |
||
− | result = result .. Text |
||
− | else |
||
− | result = result .. Shared.round(Text, Digits) |
||
− | end |
||
− | if (Addon ~= nil) then result = result .. p.doPlural(Addon, Text) end |
||
− | result = result .. '\n|}' |
||
− | result = result .. '\n</div>' |
||
− | end |
||
− | return result |
||
end |
end |
||
+ | --- Main frame invokable function to access any formatted attribute/column/key of a weapon entry. |
||
− | -- Returns a list of weapons for a stance |
||
+ | -- See default table in M:Weapons to see all valid computed attributes. |
||
− | -- Adds a ✓ if the weapon matches the polarity |
||
− | function |
+ | -- @function p.getFormattedValue |
+ | -- @param {string} weap Weapon name in EN locale |
||
− | |||
+ | -- @param {number} atk Attacks table index |
||
− | local StanceName = frame.args ~= nil and frame.args[1] or frame |
||
+ | -- @param {string} k Key name |
||
− | local Stance = Mod.getStance(StanceName) |
||
+ | -- @return Formatted value associated with k key |
||
− | |||
+ | function p.getFormattedValue(frame) |
||
− | if (Stance == nil) then |
||
+ | local weap, key, atk = (function(t) return t[1], t[2], t[3] end)(frame.args) |
||
− | return "ERREUR : " .. StanceName .. " introuvable" |
||
+ | weap = p._getWeapon(weap) |
||
− | end |
||
+ | return p._getFormattedValue(weap, key, atk) |
||
− | |||
− | local stancePvP = Mod._getValue(Stance.Name, "PVP") |
||
− | local weaps = getMeleeWeapons(Stance.Class, stancePvP) |
||
− | local result = '' |
||
− | |||
− | for i, weap in Shared.skpairs(weaps) do |
||
− | if (weap.Name ~= 'Désarmé') then |
||
− | result = result .. '\n*' .. |
||
− | Tooltip._tooltipText(weap.Name, 'Weapon', nil, |
||
− | stancePvP) |
||
− | if (weap.StancePolarity ~= nil) then |
||
− | local weapStancePolIcon = Icon._Pol(weap.StancePolarity) |
||
− | local modPolIcon = Icon._Pol( |
||
− | Mod._getValue(Stance.Name, "POLARITY")) |
||
− | if (weapStancePolIcon == modPolIcon) then |
||
− | result = result .. " ✓" |
||
− | end |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | return result |
||
end |
end |
||
+ | --- Builds a melee weapon gallery as seen on [[Template:MeleeCategory]]. |
||
− | -- Returns a list of stances for a weapon |
||
+ | -- @function p.getMeleeWeaponGallery |
||
− | -- Adds the polarity for each stance |
||
+ | -- @param {table} frame Frame object w/ first argumenting being string meleeClass |
||
− | function p.getWeaponStanceList(frame) |
||
+ | -- @returns {string} Resultant wikitext of gallery |
||
− | local WeaponName = frame.args ~= nil and frame.args[1] or frame |
||
+ | function p.getMeleeWeaponGallery(frame) |
||
− | local Weapon = p.getWeapon(WeaponName) |
||
+ | local meleeClass = frame.args[1] or '' |
||
− | |||
+ | local result = { "== Armes de type : "..meleeClass.."==", '<gallery widths="200" position="center" spacing="small">' } |
||
− | if (Weapon == nil) then return "ERROR: " .. WeaponName .. " not found" end |
||
+ | for i, weap in ipairs(p._getMeleeWeapons(meleeClass)) do |
||
− | |||
+ | table.insert(result, p._statRead(weap, nil, 'Image')..'|'..p._statFormat(weap, nil, 'Name')) |
||
− | return getWeaponStanceList(Weapon) |
||
+ | end |
||
+ | table.insert(result, '</gallery>') |
||
+ | return frame:preprocess(table.concat(result, '\n')) -- annoying that it needs to be preprocessed |
||
end |
end |
||
+ | --- Gets the total count of weapons as used on [[Mastery Rank#Total Mastery]]. |
||
− | local function getWeaponGallery(Weapons) |
||
+ | -- @function p.getWeaponCount |
||
− | local result = '{| style="margin:auto;text-align:center;"' |
||
+ | -- @param {table} frame Frame object w/ the first argument being the weaponSlot and the |
||
− | local nameRow = '' |
||
+ | -- second argument being a boolean to getFullList |
||
− | for i, Weapon in pairs(Weapons) do |
||
+ | -- @returns {number} Total count of weapons in a certain category/type |
||
− | local theImage = Weapon.Image ~= nil and Weapon.Image or "Panel.png" |
||
+ | -- @returns {table} List of weapon names that count for mastery in a particular weapon slot |
||
− | local weapLink = p._getLink(Weapon.Name) |
||
+ | function p._getWeaponCount(slot) |
||
− | if ((i - 1) % 4 == 0) then |
||
+ | slot = slot and slot:lower() |
||
− | result = result .. nameRow .. '\n|-' |
||
+ | local data = slot and WeaponData[slot] or WeaponData |
||
− | nameRow = '\n|-' |
||
+ | local fullList = {} |
||
− | end |
||
+ | |||
− | result = result .. '\n| style="width:165px" |[[File:' .. theImage .. |
||
+ | for name, weapon in pairs(data) do |
||
− | '|150px|link=' .. Weapon.Name .. ']]' |
||
+ | if not weapon._IgnoreInMasteryCount then |
||
− | nameRow = nameRow .. '\n| style="vertical-align: text-top;" |[[' .. |
||
+ | -- TODO: There should be a better way to determine/differentiate if a weapon is a kitgun b/c kitguns and zaws |
||
− | weapLink .. '|' .. Weapon.Name .. ']]' |
||
+ | -- are stored in the same M:Weapons/data/modular data store; add a new "Kitgun" or "Zaw" Trait and target that? |
||
− | end |
||
+ | if (slot == 'kitgun' and weapon.Slot == 'Secondaire') |
||
− | result = result .. nameRow |
||
+ | or (slot == 'zaw' and weapon.Slot == 'Mêlée') |
||
− | result = result .. '\n|}' |
||
+ | or (slot == 'robotic' and weapon.Slot ~= 'Molosse') |
||
− | return result |
||
+ | or (weapon.Slot:lower() == slot) |
||
− | end |
||
+ | or slot == nil then |
||
+ | fullList[#fullList + 1] = name |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | return #fullList, fullList |
||
− | 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 = "==Armes de type " .. Type .. "==\n" |
||
− | result = result .. getWeaponGallery(WeapArray) |
||
− | return result |
||
end |
end |
||
+ | --- Gets the total count of weapons as used on [[Mastery Rank#Total Mastery]]. |
||
+ | -- @function p.getWeaponCount |
||
+ | -- @param {table} frame Frame object w/ the first argument being the weapon slot |
||
+ | -- @return {number} Total number of weapons that can reward Mastery XP |
||
function p.getWeaponCount(frame) |
function p.getWeaponCount(frame) |
||
− | + | return (p._getWeaponCount(frame.args and frame.args[1] or nil)) |
|
− | local getFullList = frame.args ~= nil and frame.args[2] |
||
− | if getFullList == "nil" then -- bleh, this lovely parsing of invokes.. |
||
− | getFullList = nil |
||
− | end |
||
− | local getAll = frame.args ~= nil and frame.args[3] |
||
− | local count = 0 |
||
− | local fullList = "" |
||
− | for i, val in Shared.skpairs(WeaponData["Weapons"]) do |
||
− | if (not Shared.contains(WeaponData["IgnoreInCount"], i) and getAll ~= |
||
− | "true") or getAll == "true" 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 == "Principale" or val.Type == "Secondaire" or |
||
− | val.Type == "Mêlée") 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 |
||
− | elseif (Type == "Rest") then |
||
− | if (val.Type ~= "Arch-Gun" and val.Type ~= "Arch-Melee" and |
||
− | val.Type ~= "Principale" and val.Type ~= "Secondaire" and |
||
− | val.Type ~= "Mêlée") 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 |
end |
||
+ | --- Builds wikitable of all weapons' innate polarities as seen on [[Polarity]]. |
||
− | local function getSecondaryCategory(weapon) |
||
+ | -- @function p.getPolarityTable |
||
− | local class = getValue(weapon, "Class", true) |
||
+ | -- @param {table} frame Frame object |
||
− | if (class == "Jet") then |
||
+ | -- @returns {string} Wikitext of resultant wikitable |
||
− | return "Jet" |
||
+ | function p.getPolarityTable(frame) |
||
− | elseif (class == "Doubles Fusils à Pompe de Poche" or class == |
||
+ | local colNames = { 'Principale', 'Secondaire', 'Mêlée', 'Arch-Fusil', 'Arch-Mêlée' } |
||
− | "Fusil à Pompe de Poche") then |
||
+ | local cols = {} -- Will look like: {['Primary']={},['Secondary']={},['Melee']={},['Arch-Gun']={},['Arch-Melee']={},} |
||
− | return "Fusil à Pompe" |
||
+ | local colOrder = {} --{cols['Primary'],cols['Secondary'],cols['Melee'],cols['Arch-Gun'],cols['Arch-Melee'],} |
||
− | else |
||
+ | local colCounts = {} |
||
− | local trigger = getValue(weapon, "Trigger", true) |
||
− | if (trigger == "Semi-Auto" or trigger == "Rafale") then |
||
− | return "Semi-Auto" |
||
− | elseif (trigger == "Auto" or trigger == "Auto à Chauffe") then |
||
− | return "Auto" |
||
− | end |
||
− | end |
||
− | return "Other" |
||
− | end |
||
+ | for i, v in ipairs(colNames) do |
||
− | local function getPrimaryCategory(weapon) |
||
+ | cols[v] = {} |
||
− | local class = getValue(weapon, "Class", true) |
||
+ | colOrder[i] = cols[v] |
||
− | if (class == "Fusil à Pompe") then |
||
+ | colCounts[v] = 0 |
||
− | return "Fusil à Pompe" |
||
+ | end |
||
− | elseif (class == "Arc") then |
||
− | return "Arc" |
||
− | elseif (class == "Fusil de Sniper") then |
||
− | return "Fusil de Sniper" |
||
− | elseif (class == "Fusil") then |
||
− | local trigger = getValue(weapon, "Trigger", true) |
||
− | if (trigger == "Semi-Auto" or trigger == "Rafale") then |
||
− | return "Semi-Auto" |
||
− | elseif (trigger == "Auto" or trigger == "Auto à Chauffe") then |
||
− | return "Auto" |
||
− | end |
||
− | end |
||
− | return "Other" |
||
− | end |
||
+ | for _, weapon in pairs(WeaponData) do |
||
− | function p.getPolarityTable() |
||
+ | local pols = Table.size(weapon["Polarities"] or {}) |
||
− | local tHeader = "" |
||
+ | local slot = weapon['Slot'] |
||
− | tHeader = tHeader .. |
||
+ | if pols > 0 and cols[slot] then |
||
− | '\n{| style="width: 100%; border-collapse: collapse; cellpadding: 2" border="1"' |
||
+ | table.insert(cols[slot], { |
||
− | tHeader = tHeader .. '\n! colspan="2" |Armes Principale' |
||
+ | '|'..p._getFormattedValue(weapon, 'NameLink'):gsub(' ?%(.*%)', '')..'||'..p._getFormattedValue(weapon, "Polarities"), |
||
− | tHeader = tHeader .. '\n! colspan="2" |Armes Secondaire' |
||
+ | pols |
||
− | tHeader = tHeader .. '\n! colspan="2" |Armes Mêlée' |
||
+ | }) |
||
− | local tRows = "" |
||
+ | colCounts[slot] = colCounts[slot] + 1 |
||
+ | end |
||
+ | end |
||
+ | for i, v in ipairs(colNames) do |
||
− | local Melees = p.getWeapons(function(x) |
||
+ | colCounts[i] = colCounts[v] |
||
− | return p.isMelee(x) and |
||
+ | table.sort(cols[v], function(a, b)return a[2] > b[2] end) |
||
− | Shared.tableCount(getValue(x, "Polarities", true)) > 0 |
||
− | + | end |
|
− | local Pistols = p.getWeapons(function(x) |
||
− | return x.Type == "Secondaire" and |
||
− | Shared.tableCount(getValue(x, "Polarities", true)) > 0 |
||
− | end) |
||
− | local Primaries = p.getWeapons(function(x) |
||
− | return (x.Type == "Principale") and |
||
− | Shared.tableCount(getValue(x, "Polarities", true)) > 0 |
||
− | end) |
||
− | + | local result = {[=[ |
|
+ | {| style="width: 100%; border-collapse: collapse;" cellpadding="2" border="1" |
||
− | local maxLen = ACount |
||
+ | |+ '''Armes avec une Polarité innée (en ignorant la Posture et l'emplacement Exilus)''' |
||
− | local BCount = Shared.tableCount(Pistols) |
||
+ | ! colspan="2" |Principales |
||
− | if (BCount > maxLen) then maxLen = BCount end |
||
+ | ! colspan="2" |Secondaires |
||
− | local CCount = Shared.tableCount(Primaries) |
||
+ | ! colspan="2" |Mêlées |
||
− | if (CCount > maxLen) then maxLen = CCount end |
||
+ | ! colspan="2" |Arch-Fuils |
||
− | |||
+ | ! colspan="2" |Arch-Mêlées]=]} |
||
− | for i = 1, maxLen, 1 do |
||
+ | for i = 1, math.max(table.unpack(colCounts)) do --row |
||
− | tRows = tRows .. "\n|-" |
||
+ | table.insert(result, '|-') |
||
− | if (i <= CCount) then |
||
+ | for _, col in ipairs(colOrder) do --cell |
||
− | tRows = tRows .. "\n|[[" .. Primaries[i].Name .. "]]||" .. |
||
+ | table.insert(result,(col[i] or {'| ||'})[1]) |
||
− | p.GetPolarityString(Primaries[i]) |
||
+ | end |
||
− | else |
||
+ | end |
||
− | tRows = tRows .. "\n| ||" |
||
+ | table.insert(result, '|}') |
||
− | end |
||
+ | return table.concat(result, '\n') |
||
− | 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 |
end |
||
+ | --- Builds a table that lists out all weapons with a certain damage type |
||
− | local function buildCompareString(Val1, Val2, ValName, Digits, Addon, Words, |
||
+ | -- @function p.buildDamageTypeTable |
||
− | Start, Middle) |
||
+ | -- @param {table} frame Frame object |
||
− | if (Val1 == nil or Val2 == nil) then return "" end |
||
+ | -- @returns {string} Wikitext of resultant wikitable |
||
− | local V1Str = Val1 |
||
+ | function p.buildDamageTypeTable(frame) |
||
− | local V2Str = Val2 |
||
+ | local damageType = frame.args and frame.args[1] or frame |
||
− | if (Digits ~= nil) then |
||
+ | local mostly = frame.args and (frame.args[2] or '') ~= '' |
||
− | 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 "Plus de" |
||
− | local smallWord = Words ~= nil and Words[2] or "Moins de" |
||
− | local start = Start ~= nil and Start or "\n**" |
||
− | local bigMiddle = Middle ~= nil and Middle[1] or "" |
||
− | local smallMiddle = Middle ~= nil and Middle[2] or "" |
||
+ | local content = {} |
||
− | if (Val1 > Val2) then |
||
+ | for k,weap in pairs(WeaponData) do |
||
− | return start .. " " .. bigWord .. " " .. ValName .. " " .. bigMiddle .. |
||
+ | local weapAtk = getWeaponAttack(weap)--could add a loop here |
||
− | " (" .. V1Str .. " vs. " .. V2Str .. ")" |
||
+ | local portion, biastype, damage = statRead(weapAtk, 'DamageBias') |
||
− | elseif (Val2 > Val1) then |
||
+ | local typeDmg = statRead(weapAtk, damageType) |
||
− | return |
||
+ | if damage == 0 then typeDmg = weapAtk[damageType] and 1 or 0 end--modular pieces |
||
− | start .. " " .. smallWord .. " " .. ValName .. " " .. smallMiddle .. |
||
+ | --Filter for |
||
− | " (" .. V1Str .. " vs. " .. V2Str .. ")" |
||
+ | --a. any of the damage type in any attack - former 'not mostly' |
||
− | else |
||
+ | --b. at least one majority damage type - former 'mostly' |
||
− | return "" |
||
+ | --c. a majority of the damage type in the display attack - 'mostly' |
||
− | end |
||
+ | --d. any of the damage type in the display attack - 'not mostly' |
||
− | end |
||
+ | if biastype == damageType or not mostly and typeDmg > 0 then |
||
− | |||
+ | table.insert(content, ('| %s || %s || %s || %s || %s || data-sort-value="%s" | %s'):format( |
||
− | local function buildGunComparisonString(Weapon1, Weapon2, Conclave) |
||
+ | statFormat(weapAtk, 'Name'), |
||
− | local result = "" |
||
+ | statRead(weapAtk, 'Slot'), |
||
− | if (Conclave) then |
||
+ | statRead(weapAtk, 'Class'), |
||
− | result = "* " .. Weapon1.Name .. ", comparé au [[Conclave:" .. |
||
+ | statRead(weapAtk, 'AttackName'), |
||
− | Weapon2.Name .. "|" .. Weapon2.Name .. "]]:" |
||
+ | typeDmg, |
||
− | else |
||
+ | portion, statFormat(weapAtk, 'DamageBias') |
||
− | result = "* " .. Weapon1.Name .. ", comparé au [[" .. Weapon2.Name .. |
||
+ | )) |
||
− | "]]:" |
||
− | + | end |
|
+ | end |
||
− | |||
+ | table.sort(content)--will sort by tooltip span key |
||
− | 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), |
||
− | "dégâts de base", {2, 1}) |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Impact"], |
||
− | Att2.Damage["Impact"], |
||
− | " dégâts " .. |
||
− | Icon._Proc("Impact", "text"), |
||
− | {2, 1}, nil, {"Plus de", "Moins de"}, |
||
− | "\n***") |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Perforation"], |
||
− | Att2.Damage["Perforation"], |
||
− | " dégâts " .. |
||
− | Icon._Proc("Perforation", "text"), |
||
− | {2, 1}, nil, {"Plus de", "Moins de"}, |
||
− | "\n***") |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Tranchant"], |
||
− | Att2.Damage["Tranchant"], |
||
− | " dégâts " .. |
||
− | Icon._Proc("Tranchant", "text"), |
||
− | {2, 1}, nil, {"Plus de", "Moins de"}, |
||
− | "\n***") |
||
− | if (string.len(dmgString) > 0 and GetDamage(Att1) == GetDamage(Att2)) then |
||
− | dmgString = |
||
− | "\n**Dégâts de base équivalent, mais composition différente:" .. |
||
− | dmgString |
||
− | end |
||
− | result = result .. dmgString |
||
− | end |
||
− | if (hasAttack(Weapon1, "Charge") and hasAttack(Weapon2, "Charge")) then |
||
− | local Att1 = getAttack(Weapon1, "Charge") |
||
− | local Att2 = getAttack(Weapon2, "Charge") |
||
− | -- local addedString = "" |
||
− | -- if(dontHasAttack(Weapon1, "Normal")and dontHasAttack(Weapon2, "Normal")) then |
||
− | -- addedString = "charged test" |
||
− | -- end |
||
− | if (Att1.CritChance ~= nil and Att2.CritChance ~= nil) then |
||
− | if (dontHasAttack(Weapon1, "Normal") and |
||
− | dontHasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]]", |
||
− | 2, "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]] avec un tir chargé", |
||
− | 2, "%") |
||
− | end |
||
− | end |
||
− | if (dontHasAttack(Weapon1, "Normal") and |
||
− | dontHasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]]", 2, |
||
− | "x") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]] avec un tir chargé", |
||
− | 2, "x") |
||
− | end |
||
− | if (Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then |
||
− | if (dontHasAttack(Weapon1, "Normal") and |
||
− | dontHasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]]", 2, "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]] avec un tir chargé", |
||
− | 2, "%") |
||
− | end |
||
− | end |
||
− | if (dontHasAttack(Weapon1, "Normal") and |
||
− | dontHasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString(GetDamage(Weapon1.ChargeAttack), |
||
− | GetDamage(Weapon2.ChargeAttack), |
||
− | "dégâts", {2, 1}) |
||
− | end |
||
− | if (hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Normal")) then |
||
− | result = result .. |
||
− | buildCompareString(GetDamage(Weapon1.ChargeAttack), |
||
− | GetDamage(Weapon2.ChargeAttack), |
||
− | "dégâts avec un tir chargé", |
||
− | {2, 1}) |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(getValue(Weapon1, |
||
− | {"Charge", "ChargeTime"}), |
||
− | getValue(Weapon2, |
||
− | {"Charge", "ChargeTime"}), |
||
− | "Temps de charge", {2, 1}, " s", |
||
− | {"", ""}, nil, |
||
− | {"plus lent", "plus rapide"}) |
||
− | end |
||
− | if (hasAttack(Weapon1, "Area") and hasAttack(Weapon2, "Area")) then |
||
− | result = result .. |
||
− | buildCompareString(GetDamage(Weapon1.AreaAttack), |
||
− | GetDamage(Weapon2.AreaAttack), |
||
− | "dégâts de zone", {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}) |
||
− | -- test code to fix stradavar wrong comparison |
||
− | local Att1 = getAttack(Weapon1, "Secondary") |
||
− | local Att2 = getAttack(Weapon2, "Secondary") |
||
− | if (Att1.CritChance ~= nil and Att2.CritChance ~= nil) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]] sur le [[Tir Alternatif]]", |
||
− | 2, "%") |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]] sur le [[Tir Alternatif]]", |
||
− | 2, "x") |
||
− | if (Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]] sur le [[Tir Alternatif]]", |
||
− | 2, "%") |
||
− | end |
||
− | result = result .. buildCompareString(Att1.FireRate, Att2.FireRate, |
||
− | "[[Cadence de Tir]] sur le [[Tir Alternatif]]", |
||
− | 2, " balle<s>/s") |
||
− | -- end of test code |
||
− | end |
||
− | |||
− | -- test code to fix tiberon prime comparison |
||
− | |||
− | if ((hasAttack(Weapon1, "Normal") and hasAttack(Weapon2, "Secondary") and |
||
− | dontHasAttack(Weapon1, "Secondary")) or |
||
− | (hasAttack(Weapon1, "Secondary") and hasAttack(Weapon2, "Normal") and |
||
− | dontHasAttack(Weapon2, "Secondary"))) 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), |
||
− | "[[Chance de Coup Critique]]", 2, |
||
− | "%") |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]]", 2, "x") |
||
− | |||
− | if (Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]]", 2, "%") |
||
− | end |
||
− | end |
||
− | |||
− | -- end of test code to fix tiberon prime comparison |
||
− | |||
− | 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 |
||
− | if (dontHasAttack(Weapon1, "Charge") and |
||
− | dontHasAttack(Weapon2, "Charge") and |
||
− | dontHasAttack(Weapon1, "Secondary") and |
||
− | dontHasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]]", |
||
− | 2, "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Charge") and hasAttack(Weapon2, "Charge")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "base [[Chance de Coup Critique]]", |
||
− | 2, "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Secondary") and |
||
− | hasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]] sur le tir principal", |
||
− | 2, "%") |
||
− | end |
||
− | end |
||
− | if (dontHasAttack(Weapon1, "Charge") and |
||
− | dontHasAttack(Weapon2, "Charge") and |
||
− | dontHasAttack(Weapon1, "Secondary") and |
||
− | dontHasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]]", 2, |
||
− | "x") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Charge") and hasAttack(Weapon2, "Charge")) then |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "base [[Multiplicateur de Critique]]", |
||
− | 2, "x") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Secondary") and hasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, |
||
− | Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]] sur le tir principal", |
||
− | 2, "x") |
||
− | end |
||
− | if (Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then |
||
− | if (dontHasAttack(Weapon1, "Charge") and |
||
− | dontHasAttack(Weapon2, "Charge") and |
||
− | dontHasAttack(Weapon1, "Secondary") and |
||
− | dontHasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]]", 2, "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Charge") and hasAttack(Weapon2, "Charge")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "base [[Chance de Statut]]", 2, |
||
− | "%") |
||
− | end |
||
− | if (hasAttack(Weapon1, "Secondary") and |
||
− | hasAttack(Weapon2, "Secondary")) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]] sur le tir principal", |
||
− | 2, "%") |
||
− | end |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Att1.FireRate, Att2.FireRate, |
||
− | "[[Cadence de Tir]]", 2, " balle<s>/s") |
||
− | |||
− | -- Handling Damage Falloff |
||
− | if (Att1.Falloff ~= nil and Att2.Falloff == nil) then |
||
− | result = result .. "\n** " .. Att1.Falloff.StartRange .. "m - " .. |
||
− | Att1.Falloff.EndRange .. "m dégradation dégâts" |
||
− | if (Att1.Falloff.Reduction ~= nil) then |
||
− | result = result .. " avec jusqu'à " .. |
||
− | (Att1.Falloff.Reduction * 100) .. |
||
− | "% réduction dégâts" |
||
− | 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) .. |
||
− | "% réduction dégâts" |
||
− | 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, "%", |
||
− | {"Plus grand", "Plus petit"}) |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | result = result .. |
||
− | buildCompareString(Weapon1.Magazine, Weapon2.Magazine, |
||
− | "chargeur", 0, " balle<s>", |
||
− | {"Plus gros", "Plus petit"}) |
||
− | result = result .. |
||
− | buildCompareString(Weapon1.MaxAmmo, Weapon2.MaxAmmo, |
||
− | "Réserve de munition", 0, " balle<s>", |
||
− | {"", ""}, nil, |
||
− | {"plus grande", "plus petite"}) |
||
− | -- If this is a weapon that regenerates ammo, flip the comparison |
||
− | if (Weapon1.ReloadStyle ~= nil and Weapon1.ReloadStyle == "Regenerate") then |
||
− | result = result .. |
||
− | buildCompareString(Weapon1.Reload, Weapon2.Reload, |
||
− | "[[Rechargement]]", 2, " balle<s>/s", |
||
− | {"", ""}, nil, |
||
− | {"plus lent", "plus rapide"}) |
||
− | else |
||
− | result = result .. |
||
− | buildCompareString(Weapon1.Reload, Weapon2.Reload, |
||
− | "[[Rechargement]]", 2, " s", {"", ""}, |
||
− | nil, {"plus lent", "plus rapide"}) |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Weapon1.Spool, Weapon2.Spool, "temps de chauffe", 0, |
||
− | " balle<s>", nil, {"plus lent", "plus rapide"}) |
||
− | local Acc1 = getValue(Weapon1, "Accuracy") |
||
− | local Acc2 = getValue(Weapon2, "Accuracy") |
||
− | if (type(Acc1) == "number" and type(Acc2) == "number") then |
||
− | result = result .. |
||
− | buildCompareString(Acc1, Acc2, "[[Précision]]", 0, nil, |
||
− | {"Meilleure", "Moins bonne"}) |
||
− | 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 Radial Effects|Syndicate Effect]]: [[" .. |
||
− | Weapon1.SyndicateEffect .. "]] vs. [[" .. |
||
− | Weapon2.SyndicateEffect .. "]]" |
||
− | end |
||
− | |||
− | -- Handling Polarities |
||
− | local Pol1 = Weapon1.Polarities ~= nil and Weapon1.Polarities or {} |
||
− | local Pol2 = Weapon2.Polarities ~= nil and Weapon2.Polarities or {} |
||
− | local count1 = Shared.tableCount(Pol1) |
||
− | local count2 = Shared.tableCount(Pol2) |
||
− | local isDifferent = count1 ~= count2 |
||
− | if (not isDifferent and count1 > 0) then |
||
− | table.sort(Pol1, function(x, y) return x < y end) |
||
− | table.sort(Pol2, function(x, y) return x < y end) |
||
− | for i, pol in pairs(Pol1) do |
||
− | if (pol ~= Pol2[i]) then isDifferent = true end |
||
− | end |
||
− | end |
||
− | |||
− | if (isDifferent) then |
||
− | result = result .. "\n** Différentes polarités (" .. |
||
− | p.GetPolarityString(Weapon1) .. " vs. " .. |
||
− | p.GetPolarityString(Weapon2) .. ")" |
||
− | end |
||
+ | return ([[ |
||
− | result = result .. buildCompareString(Weapon1.Mastery, Weapon2.Mastery, |
||
+ | {| class = "listtable sortable" style="margin:auto;" |
||
− | "[[Rang de Maîtrise]] requis", 0, |
||
+ | |+ '''Armes avec des dégâts %s%s''' |
||
− | nil, {"", ""}, nil, |
||
+ | |- |
||
− | {"supérieur", "inférieur"}) |
||
+ | ! Nom !! Emplacement !! Classe !! Nom de l'attaque !! data-sort-type="number" | %s !! data-sort-type="number" | Majorité |
||
− | result = result .. |
||
+ | |- |
||
− | buildCompareString(Weapon1.Disposition, Weapon2.Disposition, |
||
+ | ]]):format(mostly and 'mostly ' or '', damageType, Tooltip.full(damageType, 'DamageTypes')) |
||
− | "[[Mod_Riven#Disposition|disposition]]", 2) |
||
+ | ..table.concat(content, '\n|-\n')..'\n|}' |
||
− | return result |
||
end |
end |
||
+ | --- _isVariant adapter for p._shortLinkList |
||
− | local function buildMeleeComparisonString(Weapon1, Weapon2, Conclave) |
||
− | + | local function variantOf(weap) |
|
+ | local full, _, var, base = weap.Name, p._isVariant(weap.Name) |
||
− | if (Conclave) then |
||
+ | return var, base, full |
||
− | result = "* " .. Weapon1.Name .. ", comparé au [[Conclave:" .. |
||
− | Weapon2.Name .. "|" .. Weapon2.Name .. "]]:" |
||
− | else |
||
− | result = "* " .. Weapon1.Name .. ", comparé au [[" .. Weapon2.Name .. |
||
− | "]]:" |
||
− | end |
||
− | |||
− | local dmgString = "" |
||
− | local Att1 = getAttack(Weapon1, "Normal") |
||
− | local Att2 = getAttack(Weapon2, "Normal") |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(GetDamage(Att1), GetDamage(Att2), |
||
− | "dégâts de base", {2, 1}) |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Impact"], |
||
− | Att2.Damage["Impact"], " dégâts " .. |
||
− | Icon._Proc("Impact", "text"), {2, 1}, |
||
− | nil, {"Plus de", "Moins de"}, "\n***") |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Perforation"], |
||
− | Att2.Damage["Perforation"], |
||
− | " dégâts " .. |
||
− | Icon._Proc("Perforation", "text"), |
||
− | {2, 1}, nil, {"Plus de", "Moins de"}, |
||
− | "\n***") |
||
− | dmgString = dmgString .. |
||
− | buildCompareString(Att1.Damage["Tranchant"], |
||
− | Att2.Damage["Tranchant"], |
||
− | " dégâts " .. |
||
− | Icon._Proc("Tranchant", "text"), |
||
− | {2, 1}, nil, {"Plus de", "Moins de"}, |
||
− | "\n***") |
||
− | if (string.len(dmgString) > 0 and GetDamage(Att1) == GetDamage(Att2)) then |
||
− | dmgString = |
||
− | "\n**Dégâts de base équivalent, mais composition différente:" .. |
||
− | dmgString |
||
− | end |
||
− | result = result .. dmgString |
||
− | |||
− | if (Att1.CritChance ~= nil and Att2.CritChance ~= nil) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.CritChance * 100), |
||
− | (Att2.CritChance * 100), |
||
− | "[[Chance de Coup Critique]]", 2, "%") |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Att1.CritMultiplier, Att2.CritMultiplier, |
||
− | "[[Multiplicateur de Critique]]", {2, 1}, |
||
− | "x") |
||
− | |||
− | if (Att1.StatusChance ~= nil and Att2.StatusChance ~= nil) then |
||
− | result = result .. |
||
− | buildCompareString((Att1.StatusChance * 100), |
||
− | (Att2.StatusChance * 100), |
||
− | "[[Chance de Statut]]", 2, "%") |
||
− | end |
||
− | result = result .. |
||
− | buildCompareString(Att1.FireRate, Att2.FireRate, |
||
− | "[[Vitesse d'Attaque]]", 2) |
||
− | result = result .. buildCompareString(Icon._Pol(Weapon1.StancePolarity), |
||
− | Icon._Pol(Weapon2.StancePolarity), |
||
− | "polarité de [[Posture]]", nil, nil, |
||
− | {"Différente", "Différente"}) |
||
− | result = result .. |
||
− | buildCompareString(getValue(Weapon1, "ChannelMult", true), |
||
− | getValue(Weapon2, "ChannelMult", true), |
||
− | "Multiplicateur de Canalisation", 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** Polarités différentes (" .. |
||
− | p.GetPolarityString(Weapon1) .. " vs. " .. |
||
− | p.GetPolarityString(Weapon2) .. ")" |
||
− | end |
||
− | |||
− | result = result .. buildCompareString(Weapon1.Mastery, Weapon2.Mastery, |
||
− | "[[Rang de Maîtrise]] requis", 0) |
||
− | return result |
||
end |
end |
||
+ | --- Builds a list of weapons, with variants being next to base weapon name inside parentheses |
||
− | function p.buildComparison(frame) |
||
+ | -- (e.g. {{Weapon|Braton}} ({{Weapon|MK1-Braton|MK1}}, {{Weapon|Braton Prime|Prime}})). |
||
− | local WeapName1 = frame.args[1] |
||
+ | -- @function p._shortLinkList |
||
− | local WeapName2 = frame.args[2] |
||
+ | -- @param {table} Weapon Weapon table |
||
− | |||
+ | -- @param {boolean} tooltip If true, adds weapon tooltips, false otherwise; defaults to false |
||
− | if (WeapName1 == nil or WeapName2 == nil) then |
||
+ | -- @returns {string} Wikitext of resultant list |
||
− | return '<span style="color:red">ERROR: Must compare two weapons</span>' |
||
+ | function p._shortLinkList(Weapons, tooltip) |
||
− | end |
||
+ | return StatObject.shortLinkList(Weapons, variantOf, tooltip and 'Weapons') |
||
− | |||
− | local Weapon1 = p.getWeapon(WeapName1) |
||
− | if (Weapon1 == nil) then |
||
− | return '<span style="color:red">ERROR: Could not find ' .. WeapName1 .. |
||
− | '</span>' |
||
− | end |
||
− | local Weapon2 = p.getWeapon(WeapName2) |
||
− | if (Weapon2 == nil) then |
||
− | return '<span style="color:red">ERROR: Could not find ' .. WeapName2 .. |
||
− | '</span>' |
||
− | end |
||
− | |||
− | if (p.isMelee(Weapon1)) then |
||
− | return buildMeleeComparisonString(Weapon1, Weapon2) -- .."[[Category:Automatic Comparison]]" |
||
− | else |
||
− | return buildGunComparisonString(Weapon1, Weapon2) -- .."[[Category:Automatic Comparison]]" |
||
− | end |
||
end |
end |
||
+ | --- Builds a list of weapons' mastery requirements as seen on [[Template:EquipmentUnlock]], |
||
− | function p.buildConclaveComparison(frame) |
||
+ | -- [[Template:EquipmentUnlock/Primary]], [[Template:EquipmentUnlock/Secondary]], |
||
− | local WeapName1 = frame.args[1] |
||
+ | -- [[Template:EquipmentUnlock/Melee]], etc. |
||
− | local WeapName2 = frame.args[2] |
||
+ | -- @function p.getMasteryShortList |
||
− | |||
+ | -- @param {table} frame Frame object w/ first argument being a string weaponSlot |
||
− | if (WeapName1 == nil or WeapName2 == nil) then |
||
+ | -- @returns {string} Wikitext of resultant list |
||
− | return '<span style="color:red">ERROR: Must compare two weapons</span>' |
||
+ | function p.getMasteryShortList(frame) |
||
− | end |
||
+ | local weaponSlot = frame.args[1] |
||
− | |||
+ | local masteryRank = tonumber(frame.args[2]) |
||
− | local Weapon1 = p.getConclaveWeapon(WeapName1) |
||
+ | local weapArray = p._getWeapons(function(x) |
||
− | if (Weapon1 == nil) then |
||
+ | return x.Slot == weaponSlot and x.Mastery == masteryRank |
||
− | return '<span style="color:red">ERROR: Could not find ' .. WeapName1 .. |
||
+ | end) |
||
− | '</span>' |
||
+ | return table.concat(StatObject.shortLinkList(weapArray, variantOf, 'Weapons'), ' • ') |
||
− | end |
||
− | local Weapon2 = p.getConclaveWeapon(WeapName2) |
||
− | if (Weapon2 == nil) then |
||
− | return '<span style="color:red">ERROR: Could not find ' .. WeapName2 .. |
||
− | '</span>' |
||
− | end |
||
− | |||
− | if (p.isMelee(Weapon1)) then |
||
− | return buildMeleeComparisonString(Weapon1, Weapon2, true) -- .."[[Category:Automatic Comparison]]" |
||
− | else |
||
− | return buildGunComparisonString(Weapon1, Weapon2, true) -- .."[[Category:Automatic Comparison]]" |
||
− | end |
||
end |
end |
||
− | function p. |
+ | function p.fullList() |
+ | return table.concat(StatObject.shortLinkList(WeaponData, variantOf, 'Weapons'), ' • ') |
||
− | local WeapName = frame.args ~= nil and frame.args[1] or frame |
||
− | if (WeapName == nil) then |
||
− | return |
||
− | '<span style="color:red">ERROR: Must provide a Weapon name</span>' |
||
− | end |
||
− | |||
− | local Weapon = p.getWeapon(WeapName) |
||
− | if (Weapon == nil) then |
||
− | return '<span style="color:red">ERROR: Could not find ' .. WeapName .. |
||
− | '</span>' |
||
− | end |
||
− | if (Weapon.Family == nil) then |
||
− | return '<span style="color:red">ERROR: ' .. WeapName .. |
||
− | ' doesn\'t have a family</span>' |
||
− | end |
||
− | |||
− | local relatives = getFamily(Weapon.Family) |
||
− | local result = {} |
||
− | for i, NewWeapon in pairs(relatives) do |
||
− | if (WeapName ~= NewWeapon.Name) then |
||
− | if (p.isMelee(NewWeapon)) then |
||
− | table.insert(result, |
||
− | buildMeleeComparisonString(Weapon, NewWeapon)) |
||
− | else |
||
− | table.insert(result, buildGunComparisonString(Weapon, NewWeapon)) |
||
− | end |
||
− | end |
||
− | end |
||
− | return table.concat(result, "\n") |
||
end |
end |
||
+ | --- Builds a list of PvP weapons as seen on [[PvP#Limitations]]. |
||
− | function p.buildAutoboxCategories(frame) |
||
+ | -- @function p.getConclaveList |
||
− | local WeapName = frame.args ~= nil and frame.args[1] or frame |
||
+ | -- @param {table} frame Frame object w/ first argument being a string weaponSlot |
||
− | local Weapon = p.getWeapon(WeapName) |
||
+ | -- @returns {string} Wikitext of resultant list |
||
− | local result = "[[Category:Armes]]" |
||
+ | function p.getConclaveList(frame) |
||
− | if (Weapon == nil) then |
||
+ | local weaponSlot = frame.args[1] or 'All' |
||
− | return "" |
||
+ | local weapArray = p._getWeapons(function(weap) |
||
− | elseif (Weapon.IgnoreCategories ~= nil and Weapon.IgnoreCategories) then |
||
+ | return weap.Conclave == true |
||
− | return "" |
||
+ | end, weaponSlot, {pvp=true}) |
||
− | end |
||
+ | return '*'..table.concat(StatObject.shortLinkList(weapArray, variantOf), '\n* ') |
||
− | if (Weapon.Type ~= nil) then |
||
− | if (Weapon.Type == "Arch-Mêlée") then |
||
− | result = result .. "[[Category:Arch-Mêlée]]" |
||
− | elseif (Weapon.Type == "Arch-Fusil" or Weapon.Type == |
||
− | "Arch-Fusil (Atmosphère)") then |
||
− | result = result .. "[[Category:Arch-Fusil]]" |
||
− | elseif (Weapon.Type == "Arch-Fusil (Atmosphere)") then |
||
− | result = result |
||
− | elseif (Weapon.Type == "Mêlée") then |
||
− | result = result .. "[[Category:Arme de Mêlée]]" |
||
− | elseif (Weapon.Type == "Amplificateur") then |
||
− | result = result |
||
− | else |
||
− | result = result .. "[[Category: Arme " .. Weapon.Type .. "]]" |
||
− | end |
||
− | end |
||
− | if (Weapon.Class ~= nil) then |
||
− | result = result .. "[[Category:" .. Weapon.Class .. "]]" |
||
− | end |
||
− | |||
− | local augments = Mod.getWeaponAugments(Weapon) |
||
− | if (Shared.tableCount(augments) > 0) then |
||
− | result = result .. "[[Category:Arme d'Augment]]" |
||
− | end |
||
− | |||
− | if (HasTrait(Weapon, "Prime")) then |
||
− | result = result .. "[[Category:Prime]]" |
||
− | if (HasTrait(Weapon, "Never Vaulted")) then |
||
− | result = result .. "[[Category:Never Vaulted]]" |
||
− | elseif (HasTrait(Weapon, "Vaulted")) then |
||
− | result = result .. "[[Category:Vaulted]]" |
||
− | end |
||
− | end |
||
− | |||
− | if (HasTrait(Weapon, "Grineer")) then |
||
− | result = result .. "[[Category:Armes Grineer]]" |
||
− | elseif (HasTrait(Weapon, "Corpus")) then |
||
− | result = result .. "[[Category:Armes Corpus]]" |
||
− | elseif (HasTrait(Weapon, "Infesté")) then |
||
− | result = result .. "[[Category:Armes Infesté]]" |
||
− | elseif (HasTrait(Weapon, "Tenno")) then |
||
− | result = result .. "[[Category:Armes Tenno]]" |
||
− | 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 == "Perforation" or |
||
− | bestElement == "Tranchant") then |
||
− | if (bestPercent > .38) then |
||
− | result = result .. "[[Category:Arme de Type " .. bestElement .. |
||
− | "]]" |
||
− | else |
||
− | result = result .. "[[Category:Arme de Type Equilibré]]" |
||
− | end |
||
− | end |
||
− | |||
− | for key, value in Shared.skpairs(attack.Damage) do |
||
− | if (key ~= "Impact" and key ~= "Perforation" and key ~= "Tranchant") then |
||
− | result = result .. "[[Category:Arme de Type " .. key .. "]]" |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | if (hasAttack(Weapon, "Secondaire")) then |
||
− | result = result .. "[[Category:Weapons with Alt Fire]]" |
||
− | end |
||
− | |||
− | return result |
||
− | 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 .. "|" .. Tooltip._tooltipText(Weapon.Name, 'Weapon') .. |
||
− | "||" .. Weapon.Type .. "|| " .. |
||
− | getValue(Weapon, "Class", true, true) |
||
− | if (hasAttack(Weapon, "Normal")) then |
||
− | local tempBias = getValue(Weapon, {"Normal", "DamageBias"}, true) |
||
− | local tempBiasStripped = string.match(tempBias, "(%d*)%%") |
||
− | thisRow = thisRow .. "||" .. |
||
− | getValue(Weapon, {"Normal", DamageType}) .. "||" .. |
||
− | "data-sort-value=" .. tempBiasStripped .. "|" .. |
||
− | tempBias |
||
− | elseif (hasAttack(Weapon, "Charge")) then |
||
− | local tempBias = getValue(Weapon, {"Charge", "DamageBias"}, true) |
||
− | local tempBiasStripped = string.match(tempBias, "(%d*)%%") |
||
− | thisRow = thisRow .. "||" .. |
||
− | getValue(Weapon, {"Charge", DamageType}) .. "||" .. |
||
− | "data-sort-value=" .. tempBiasStripped .. "|" .. |
||
− | tempBias |
||
− | 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["Mêlée"] ~= nil and |
||
− | Shared.tableCount(TypeTable["Mêlée"]) > 0) then |
||
− | thisTable = thisTable .. "\n===Melee===" |
||
− | local tempList = p.shortLinkList(TypeTable["Mêlée"]) |
||
− | 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 table.insert(result, pair) end |
||
− | return table.concat(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 |
end |
||
+ | --- Builds a disposition wikitable as seen on [[Riven Mods/Weapon Dispos]]. |
||
+ | -- @function p.getRivenDispositionTable |
||
+ | -- @param {table} frame Frame object w/ first argument being a string weaponSlot |
||
+ | -- @returns {string} Wikitext of resultant wikitable |
||
function p.getRivenDispositionTable(frame) |
function p.getRivenDispositionTable(frame) |
||
− | + | local weaponSlot = frame.args[1] |
|
+ | local result = { |
||
+ | '{| class="article-table" border="0" cellpadding="1" cellspacing="1" style="width: 100%"', |
||
+ | '|-', |
||
+ | {'[[a| '}, -- Wikitable header row |
||
+ | '|-' |
||
+ | } |
||
+ | -- local ranges = {'○○○○○', '●○○○○', '●●○○○', '●●●○○', '●●●●○', '●●●●●'} |
||
− | local result = |
||
+ | local dispo = {} |
||
− | '{| class="article-table" border="0" cellpadding="1" cellspacing="1" style="width: 100%"' |
||
− | result = result .. '\n|-' |
||
− | for i = 5, 1, -1 do |
||
− | local j = nil |
||
− | if (i == 5) then |
||
− | j = 1.5 |
||
− | elseif (i == 4) then |
||
− | j = 1.3 |
||
− | elseif (i == 3) then |
||
− | j = 1.1 |
||
− | elseif (i == 2) then |
||
− | j = 0.89 |
||
− | else |
||
− | j = 0.69 |
||
− | end |
||
− | result = result .. '\n! scope="col" style="text-align:center;"|' .. |
||
− | Icon._Dis(j) |
||
− | end |
||
− | result = result .. '\n|-' |
||
− | for i = 5, 1, -1 do |
||
− | result = result .. '\n| style="vertical-align:top" |' |
||
− | if (i == 5) then |
||
− | for j = 1550, 1301, -1 do |
||
− | result = result .. |
||
− | p.getRivenDispositionList( |
||
− | {args = {WeaponType, j / 1000}}) |
||
− | end |
||
− | elseif (i == 4) then |
||
− | for j = 1300, 1101, -1 do |
||
− | result = result .. |
||
− | p.getRivenDispositionList( |
||
− | {args = {WeaponType, j / 1000}}) |
||
− | end |
||
− | elseif (i == 3) then |
||
− | for j = 1100, 900, -1 do |
||
− | result = result .. |
||
− | p.getRivenDispositionList( |
||
− | {args = {WeaponType, j / 1000}}) |
||
− | end |
||
− | elseif (i == 2) then |
||
− | for j = 899, 700, -1 do |
||
− | result = result .. |
||
− | p.getRivenDispositionList( |
||
− | {args = {WeaponType, j / 1000}}) |
||
− | end |
||
− | else |
||
− | for j = 699, 500, -1 do |
||
− | result = result .. |
||
− | p.getRivenDispositionList( |
||
− | {args = {WeaponType, j / 1000}}) |
||
− | end |
||
− | end |
||
− | end |
||
− | result = result .. '\n|}' |
||
+ | for k, weapon in pairs(WeaponData) do |
||
− | return result |
||
+ | if weapon['Disposition'] and (weaponSlot == 'All' or weapon['Slot'] == weaponSlot) then |
||
− | end |
||
+ | local disp = p._statFormat(weapon, nil, 'Dispo') |
||
+ | dispo[disp] = dispo[disp] or {} |
||
+ | table.insert(dispo[disp], weapon) |
||
+ | end |
||
+ | end |
||
+ | for str, dis in Table.skpairs(dispo) do |
||
− | function p.getConclaveList(frame) |
||
+ | table.sort(dis, function(a, b) return a['Disposition'] > b['Disposition'] end) |
||
− | local WeaponType = frame.args[1] |
||
+ | local col = { '| style="vertical-align:top; font-size:small" |' } |
||
+ | for _, weap in ipairs(dis) do |
||
+ | table.insert(col, p._statFormat(weap, nil, 'NameLink')..' ('..weap['Disposition']..')') |
||
+ | end |
||
+ | table.insert(result[3], str) |
||
+ | table.insert(result, table.concat(col, '\n* ')) |
||
+ | end |
||
+ | result[3] = table.concat(result[3], ']]\n! scope="col" style="text-align:center;"|[[Mods Riven#Disposition|')..']]' |
||
− | local weapArray = p.getWeapons(function(x) |
||
+ | table.insert(result, '|}') |
||
− | if (x.Type ~= nil and x.Conclave ~= nil) then |
||
+ | return table.concat(result, '\n') |
||
− | 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 |
end |
||
+ | --- Builds a simple div in the Weapon part of the abilities if an Exalted Weapon is existing. |
||
− | -- Runs a bunch of things to quickly check if anything broke |
||
+ | -- @function p.buildAbilityWeaponTab |
||
− | function p.checkForBugs(frame) |
||
+ | -- @return <table> with weapLink, main page link, weapImg, introSection, fetched from the main Weapon page |
||
− | return p.buildComparison({args = {"Lato", "Lato Prime"}}) .. |
||
+ | function p.buildAbilityWeaponTab(frame) |
||
− | p.buildComparison({args = {"Glaive", "Glaive Prime"}}) .. |
||
+ | local abilityName = frame.args[1] |
||
− | p.getMeleeComparisonTable({}) .. |
||
+ | local AbilityWeaponTab = {} |
||
− | p.getSecondaryComparisonTable({}) |
||
− | end |
||
+ | for _, weap in pairs(WeaponData) do |
||
− | function p.checkElements(frame) |
||
+ | if weap.WeaponAugment then |
||
− | local result = "wyrd" |
||
+ | if abilityName == weap.WeaponAugment then |
||
− | for key, theWeap in Shared.skpairs(WeaponData["Weapons"]) do |
||
+ | if weap.Name ~= "Lame Exaltée Prime" and weap.Name ~= "Lame Exaltée Umbra" then -- escape duplicate entries |
||
− | for attName, Attack in p.attackLoop(theWeap) do |
||
− | + | table.insert(AbilityWeaponTab, ([==[ |
|
+ | {| id="AbilityWeaponTab" style="width: %s; background-color: #2a2a31; text-align: center; padding: 1rem;" |
||
− | if (Attack.Damage ~= nil) then |
||
− | + | |- |
|
− | + | | rowspan=2 | [[Fichier:%s|200px]] || [[%s]] |
|
− | + | |- |
|
− | + | | %s |
|
+ | |} |
||
+ | ]==]):format( |
||
+ | '100%', -- escape auto-format |
||
+ | weap.Image or 'Panel.png', |
||
+ | weap.Link or 'Lien non trouvé.[[Catégorie:AbilityWeaponTab error]]', |
||
+ | frame:expandTemplate{ title = 'fetchSection', args = {weap.Link, 'intro'} } or 'Aucune description trouvée sur la page.[[Catégorie:AbilityWeaponTab error]]' |
||
+ | )) |
||
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 |
end |
||
end |
end |
||
− | return result |
||
− | end |
||
+ | -- close and return table |
||
− | function p.checkForMissingData(frame) |
||
+ | return table.concat(AbilityWeaponTab, "") |
||
− | 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 |
end |
||
− | function p. |
+ | function p.getSignatureWeaponsTable(frame) |
+ | local signWpsTable = mw.html.create("table"):addClass("bigmodtable sortable"):css("width", "100%") -- main Table |
||
− | local Category = frame.args ~= nil and frame.args[1] or frame |
||
− | local Weapons = p.getWeapons(function(x) |
||
− | return getValue(x, "Type", true) == Category |
||
− | end) |
||
+ | -- build main Table headings |
||
− | local result = '{| style="margin:auto;text-align:center;"' |
||
+ | signWpsTable:tag("tr") |
||
− | local i = 0 |
||
+ | :tag("th"):wikitext('Warframe/Compagnon'):done() |
||
− | for key, Weapon in Shared.skpairs(Weapons) do |
||
+ | :tag("th"):attr("data-sort-type", "text"):wikitext('Arme(s)'):done() |
||
− | i = i + 1 |
||
+ | :tag("th"):addClass("unsortable"):wikitext('Synergie'):done() |
||
− | local theImage = Weapon.Image ~= nil and Weapon.Image or "Panel.png" |
||
+ | :done() |
||
− | if ((i - 1) % 7 == 0) then result = result .. '\n|-' end |
||
− | result = result .. '\n| style="width:85px" |[[File:' .. Weapon.Name .. |
||
− | '.png|70px]]' |
||
− | end |
||
− | result = result .. '\n|}' |
||
− | return result |
||
− | end |
||
+ | for key, weaps in pairs(WeaponData) do |
||
− | -- and we are back... new table building functions ! |
||
+ | if weaps.Traits then |
||
− | |||
+ | for x, traits in pairs(weaps.Traits) do |
||
− | local function BuildCompRow(Head, Weapon, UseCompDisplay) |
||
+ | if traits == "Signature" then |
||
− | -- User:Falterfire 6/12/18 - Adding new Comparison Display functionality |
||
+ | if weaps.SignatureTags and weaps.SignatureDesc then |
||
− | -- Toggled with a variable, which is false if not specified |
||
+ | local WFAndCompanions = {} |
||
− | if UseCompDisplay == nil then UseCompDisplay = false end |
||
+ | -- Ajouter les éléments de weaps.SignatureTags.Warframes |
||
− | local styleString = "" -- "border: 1px solid lightgray;" |
||
+ | if weaps.SignatureTags.Warframes then |
||
− | local td = '' |
||
+ | for _, wfs in pairs(weaps.SignatureTags.Warframes) do |
||
− | local result = '' |
||
+ | table.insert(WFAndCompanions, Tooltip.full(wfs, "Warframes")) |
||
− | local ValNameZ = nil |
||
− | local ValName = nil |
||
− | |||
− | -- User:Faltefire 6/12/18 - By default, use old version of code |
||
− | if not UseCompDisplay or Weapon.ComparisonDisplay == nil then |
||
− | local attName = "" |
||
− | if (hasAttack(Weapon, "Charge")) then |
||
− | attName = "Charge" |
||
− | elseif (hasAttack(Weapon, "Normal")) then |
||
− | attName = "Normal" |
||
− | else |
||
− | return "" |
||
− | end |
||
− | |||
− | result = '\n|-\n|' |
||
− | |||
− | for i, Hline in ipairs(Head) do |
||
− | ValName = Hline[1] |
||
− | local isName = false |
||
− | |||
− | if (type(ValName) == "table" and ValName[1] == "default") then |
||
− | ValName = {attName, ValName[2]} |
||
− | elseif (type(ValName) == "table") then |
||
− | ValName = {ValName[1], ValName[2]} |
||
− | else |
||
− | isName = string.upper(ValName) == "NAME" |
||
− | end |
||
− | |||
− | if (i == 1) then |
||
− | td = '' |
||
− | else |
||
− | td = '||' |
||
− | end |
||
− | -- Override pour le nom et link correctement |
||
− | if (getValue(Weapon, ValName) ~= nil) then |
||
− | -- Replace the default name with the name from ComparisonDisplay |
||
− | if isName then |
||
− | local weapName = getValue(Weapon, ValName) |
||
− | local weapLink = p._getLink(weapName, Weapon) |
||
− | result = |
||
− | result .. td .. 'style="' .. styleString .. '"|[[' .. |
||
− | weapLink .. '|' .. weapName .. ']]' |
||
− | elseif (Hline[2]) then |
||
− | -- Add a data sort value if requested |
||
− | 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 |
||
− | else |
||
− | -- User:Faltefire 6/12/18 - Swap to new version if ComparisonDisplay is set for this weapon and UseCompDisplay is true |
||
− | for i, row in pairs(Weapon.ComparisonDisplay) do |
||
− | local attCount = Shared.tableCount(row.Attacks) |
||
− | if attCount > 0 then |
||
− | local rowText = '\n|-\n|' |
||
− | local attName = row.Attacks[1] |
||
− | for j, Hline in ipairs(Head) do |
||
− | ValName = Hline[1] |
||
− | local KeyName = '' |
||
− | |||
− | -- If we're using the ComparisonDisplay, we're overriding the attempt to shunt to a different attack |
||
− | -- So always use attName + ValName, with one two exceptions: Damage and Name are overridden |
||
− | if (type(ValName) == "table") then |
||
− | ValName = {attName, ValName[2]} |
||
− | KeyName = string.upper(ValName[2]) |
||
− | else |
||
− | KeyName = string.upper(ValName) |
||
− | end |
||
− | |||
− | if (j == 1) then |
||
− | td = '' |
||
− | else |
||
− | td = '||' |
||
− | end |
||
− | if KeyName == 'NAME' then |
||
− | local rowName = string.gsub(row.Name, "%[NAME%]", |
||
− | Weapon.Name) |
||
− | -- Replace the default name with the name from ComparisonDisplay |
||
− | rowText = rowText .. td .. 'style="' .. styleString .. |
||
− | '"|[[' .. rowName .. '|' .. rowName .. |
||
− | ']]' |
||
− | elseif KeyName == 'DAMAGE' then |
||
− | -- For damage, go with the listed attack |
||
− | if attCount == 1 then |
||
− | rowText = rowText .. td .. 'data-sort-value="' .. |
||
− | getValue(Weapon, {attName, "Damage"}) .. |
||
− | '" style="' .. styleString .. '"|' .. |
||
− | getValue(Weapon, {attName, "Damage"}, |
||
− | true, true, true) |
||
− | else |
||
− | -- If multiple attacks are listed, show the combined damage |
||
− | local attDmg = 0 |
||
− | for k, att in pairs(row.Attacks) do |
||
− | mw.log(att) |
||
− | attDmg = |
||
− | attDmg + getValue(Weapon, {att, "Damage"}) |
||
end |
end |
||
− | rowText = rowText .. td .. 'data-sort-value="' .. |
||
− | attDmg .. '" style="' .. styleString .. |
||
− | '"|' .. attDmg |
||
end |
end |
||
− | + | -- Ajouter les éléments de weaps.SignatureTags.Companions |
|
− | if |
+ | if weaps.SignatureTags.Companions then |
− | + | for _, comps in pairs(weaps.SignatureTags.Companions) do |
|
− | + | table.insert(WFAndCompanions, Tooltip.full(comps, "Companions")) |
|
− | rowText = |
||
− | rowText .. td .. 'data-sort-value="' .. |
||
− | getValue(Weapon, ValName) .. '" style="' .. |
||
− | styleString .. '"|' .. |
||
− | getValue(Weapon, ValName, true, true, |
||
− | true) |
||
− | else |
||
− | rowText = |
||
− | rowText .. td .. 'style="' .. styleString .. |
||
− | '"|' .. |
||
− | getValue(Weapon, ValName, true, true, |
||
− | true) |
||
end |
end |
||
− | else |
||
− | rowText = rowText .. td .. 'style = "' .. |
||
− | styleString .. '"|' .. "N/A" |
||
end |
end |
||
− | end |
||
− | end |
||
− | + | -- Afficher les informations |
|
− | + | signWpsTable:tag("tr") |
|
+ | :tag("td"):wikitext(table.concat(WFAndCompanions, '<br/>')):done() |
||
− | end |
||
+ | :tag("td"):wikitext(Tooltip.full(weaps.Name, "Weapons")):done() |
||
− | end |
||
+ | :tag("td"):wikitext(weaps.SignatureDesc):done() |
||
− | |||
+ | :done() |
||
− | return result |
||
− | end |
||
− | |||
− | local function BuildCompTable(Head, Weapons, UseCompDisplay) |
||
− | |||
− | if (#Weapons > 0) then |
||
− | 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 |
||
− | local rowStr = BuildCompRow(Head, Weap, UseCompDisplay) |
||
− | tRows = tRows .. rowStr |
||
− | end |
||
− | -- mw.log(tRows) |
||
− | return tHeader .. tRows .. "\n|}" |
||
− | else |
||
− | return Shared.printTemplateError('Pas d\'armes trouvees.', |
||
− | 'BuildCompTable') |
||
− | end |
||
− | end |
||
− | |||
− | function p.getCompTableGuns(frame) |
||
− | |||
− | local compType = frame.args ~= nil and frame.args[1] |
||
− | local compCat = frame.args ~= nil and frame.args[2] or nil |
||
− | local compTrigger = frame.args ~= nil and frame.args[3] or nil |
||
− | |||
− | -- Check param |
||
− | if (compCat == '') then compCat = nil end |
||
− | if (compTrigger == '') then compTrigger = nil end |
||
− | |||
− | local wpArray = {} |
||
− | if (Shared.contains({'PRINCIPALE', 'SECONDAIRE', 'ROBOTIQUE'}, compType, |
||
− | true)) then |
||
− | wpArray = p.getWeapons(function(x) |
||
− | return weaponFilter_NonMelee(x, compType, compCat, compTrigger) |
||
− | end) |
||
− | else |
||
− | return Shared.printTemplateError('Type inconnu.', 'getCompTableGuns') |
||
− | end |
||
− | |||
− | local Head = {{"Name", false, "Name"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {"Trigger", false, "Mode de Tir"}) |
||
− | table.insert(Head, {{"default", "Damage"}, true, "[[Dégâts]]"}) |
||
− | table.insert(Head, { |
||
− | {"default", "CritChance"}, true, "[[Chance de Critique|Chance Crit.]]" |
||
− | }) |
||
− | table.insert(Head, { |
||
− | {"default", "CritMultiplier"}, true, |
||
− | "[[Multiplicateur de Critique|Multiplicateur de Crit.]]" |
||
− | }) |
||
− | table.insert(Head, |
||
− | {{"default", "StatusChance"}, true, "[[Chance de Statut]]"}) |
||
− | table.insert(Head, {{"default", "BulletType"}, false, "Type de Projectile"}) |
||
− | table.insert(Head, {{"default", "FireRate"}, true, "[[Cadence de Tir]]"}) |
||
− | table.insert(Head, { |
||
− | "Magazine", true, "[[Munitions#Capacité du Chargeur|Taille Chargeur]]" |
||
− | }) |
||
− | table.insert(Head, {"Reload", true, "[[Rechargement|Tmps. Rechargement]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | table.insert(Head, |
||
− | {"Disposition", true, "[[Mod Riven#Disposition|Disposition]]"}) |
||
− | |||
− | return BuildCompTable(Head, wpArray, true) |
||
− | 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 == "Principale") then |
||
− | WeapArray = p.getConclaveWeapons( |
||
− | function(x) |
||
− | if ((getValue(x, "Type", true) == "Principale") and |
||
− | (getValue(x, "Conclave", true) == true)) then |
||
− | if (Type ~= nil) then |
||
− | return getPrimaryCategory(x) == Type |
||
− | else |
||
− | return true |
||
end |
end |
||
− | end |
||
− | return false |
||
− | end) |
||
− | elseif (Catt == "Secondaire") then |
||
− | WeapArray = p.getConclaveWeapons( |
||
− | function(x) |
||
− | if ((getValue(x, "Type", true) == "Secondaire") and |
||
− | (getValue(x, "Conclave", true) == true)) then |
||
− | if (Type ~= nil) then |
||
− | return getSecondaryCategory(x) == Type |
||
− | else |
||
− | return true |
||
− | end |
||
− | end |
||
− | return false |
||
− | end) |
||
− | else |
||
− | return |
||
− | "\n Error : Wrong Class (use Principale or Secondaire) [[Category:Invalid Comp Table]]" |
||
− | end |
||
− | |||
− | local Head = {{"Name", false, "Name"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {"Trigger", false, "[[Fire Rate|Trigger Type]]"}) |
||
− | table.insert(Head, {{"default", "Damage"}, true, "[[Dégâts]]"}) |
||
− | table.insert(Head, {"HeadshotMultiplier", true, "HS Multiplier"}) |
||
− | table.insert(Head, {{"default", "BulletType"}, false, "Projectile Type"}) |
||
− | table.insert(Head, {"FireRate", true, "[[Fire Rate]]"}) |
||
− | table.insert(Head, { |
||
− | "Magazine", true, "[[Munitions#Magazine Capacity|Magazine Size]]" |
||
− | }) |
||
− | table.insert(Head, {"Reload", true, "[[Reload Speed|Reload Time]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | |||
− | return BuildCompTable(Head, WeapArray) |
||
− | end |
||
− | |||
− | function p.getCompTableArchGuns(frame) |
||
− | local ArchType = "Arch-Fusil" |
||
− | if (frame.args ~= nil) then |
||
− | if (frame.args[1] == "Arch-Fusil (Atmosphère)") then |
||
− | ArchType = "Arch-Fusil (Atmosphère)" |
||
− | end |
||
− | end |
||
− | |||
− | local WeapArray = {} |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | return getValue(x, "Type", true) == ArchType |
||
− | end) |
||
− | |||
− | local Head = {{"Name", false, "Name"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {"Trigger", false, "Mode de Tir"}) |
||
− | table.insert(Head, {{"default", "Damage"}, true, "[[Dégâts]]"}) |
||
− | table.insert(Head, {"CritChance", true, "[[Chance de Coup Critique]]"}) |
||
− | table.insert(Head, { |
||
− | "CritMultiplier", true, |
||
− | "[[Multiplicateur de Critique|Multiplicateur de Crit.]]" |
||
− | }) |
||
− | table.insert(Head, {"StatusChance", true, "[[Chance de Statut]]"}) |
||
− | table.insert(Head, {{"default", "BulletType"}, false, "Type de Projectile"}) |
||
− | table.insert(Head, {"FireRate", true, "[[Cadence de Tir]]"}) |
||
− | table.insert(Head, { |
||
− | "Magazine", true, "[[Ammo#Magazine Capacity|Taille Chargeur]]" |
||
− | }) |
||
− | table.insert(Head, {"Reload", true, "[[Vitesse de Rechargement]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | 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 = {{"Name", false, "Nom"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {"Class", false, "Type"}) |
||
− | table.insert(Head, {{"Normal", "Damage"}, true, "[[Dégâts|Normal]]"}) |
||
− | table.insert(Head, |
||
− | {"SlideAttack", true, "[[Mêlée#Attaque Glissée|Glissée]]"}) |
||
− | table.insert(Head, {{"default", "FireRate"}, true, "[[Vitesse d'Attaque]]"}) |
||
− | table.insert(Head, { |
||
− | "CritChance", true, "[[Chance de Coup Critique|Chance Crit.]]" |
||
− | }) |
||
− | table.insert(Head, { |
||
− | "CritMultiplier", true, |
||
− | "[[Multiplicateur de Critique|Multiplicateur Crit.]]" |
||
− | }) |
||
− | table.insert(Head, {"StatusChance", true, "[[Chance de Statut]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | table.insert(Head, {"STANCEPOLARITY", false, "[[Posture]]"}) |
||
− | table.insert(Head, |
||
− | {"Disposition", true, "[[Mod Riven#Disposition|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 = {{"Name", false, "Name"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {"Class", false, "Type"}) |
||
− | table.insert(Head, {{"Normal", "Damage"}, true, "[[Dégâts|Normal]]"}) |
||
− | table.insert(Head, |
||
− | {"SlideAttack", true, "[[Mêlée#Attaque Glissée|Glissée]]"}) |
||
− | table.insert(Head, {{"default", "FireRate"}, true, "[[Vitesse d'Attaque]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | table.insert(Head, {"STANCEPOLARITY", false, "[[Posture]]"}) |
||
− | 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-Mêlée" |
||
− | end) |
||
− | |||
− | local Head = {{"Name", false, "Name"}} |
||
− | -- better if Name is always the first column !!! |
||
− | table.insert(Head, {{"Normal", "Damage"}, true, "[[Dégâts|Normal]]"}) |
||
− | table.insert(Head, |
||
− | {"SlideAttack", true, "[[Mêlée#Attaque Glissée|Glissée]]"}) |
||
− | table.insert(Head, {{"default", "FireRate"}, true, "[[Vitesse d'Attaque]]"}) |
||
− | table.insert(Head, { |
||
− | "CritChance", true, "[[Chance de Coup Critique|Chance de Crit.]]" |
||
− | }) |
||
− | table.insert(Head, { |
||
− | "CritMultiplier", true, |
||
− | "[[Multiplicateur de Critique|Multiplicateur de Crit.]]" |
||
− | }) |
||
− | table.insert(Head, {"StatusChance", true, "[[Chance de Statut]]"}) |
||
− | table.insert(Head, {"Mastery", true, "[[Rang de Maîtrise]]"}) |
||
− | 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 == "Principale") then |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | if (getValue(x, "Type", true) == "Principale") then |
||
− | if (Type ~= nil) then |
||
− | return getPrimaryCategory(x) == Type |
||
− | else |
||
− | return true |
||
end |
end |
||
end |
end |
||
− | return false |
||
− | end) |
||
− | elseif (Catt == "Secondaire") then |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | if (getValue(x, "Type", true) == "Secondaire") then |
||
− | if (Type ~= nil) then |
||
− | return getSecondaryCategory(x) == Type |
||
− | else |
||
− | return true |
||
− | end |
||
− | end |
||
− | return false |
||
− | end) |
||
− | elseif (Catt == "Robotique") then |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | return getValue(x, "Type", true) == "Robotique" |
||
− | end) |
||
− | elseif (Catt == "Arch-Fusil") then |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | return getValue(x, "Type", true) == "Arch-Fusil" |
||
− | end) |
||
− | else |
||
− | return |
||
− | "\n Erreur : Mauvaise Class (utilisez Principale, Secondaire, Robotique, ou Arch-Fusil) [[Category:Invalid Comp Table]]" |
||
− | 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, {"Secondaire", "BulletType"}, false) == |
||
− | "Projectile") then |
||
− | table.insert(WeapArray2, Weapon) |
||
− | elseif (getValue(Weapon, {attName, "BulletType"}, false) == "Thrown") then |
||
− | table.insert(WeapArray2, Weapon) |
||
end |
end |
||
end |
end |
||
+ | signWpsTable:allDone() |
||
− | local Head = {{"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 == "Tous") then Type = nil end |
||
− | local WeapArray = {} |
||
− | if (Catt == "Mêlée") then |
||
− | WeapArray = getMeleeWeapons(Type) |
||
− | local addClass = Type == nil or Shared.contains(Type, ",") |
||
− | elseif (Catt == "Arch-Mêlée") then |
||
− | WeapArray = p.getWeapons(function(x) |
||
− | return getValue(x, "Type", true) == "Arch-Mêlée" |
||
− | end) |
||
− | else |
||
− | return |
||
− | "\n Error : Wrong Class (use Melee or Arch-Melee) [[Category:Invalid Comp Table]]" |
||
− | 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 = {{"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] |
||
− | local conclave = frame.args[2] == "true" and true |
||
− | -- there's no "Dark Split-Sword" in m:weapons/data -> setting name to dual sword variant |
||
− | if weapName == 'Épées Versatiles Sombres' then |
||
− | weapName = 'Épées Versatiles Sombres (Doubles Épées)' |
||
− | end |
||
− | |||
− | local A2Name = nil |
||
− | local A2Value = nil |
||
− | local C1Name = nil |
||
− | local C1Value = nil |
||
− | local C1Toggle = nil |
||
− | local C2Name = nil |
||
− | local C2Value = nil |
||
− | local D1Name = nil |
||
− | local D1Value = nil |
||
− | local D1Value2 = nil |
||
− | local titleText = '' |
||
− | local hasCharged = false |
||
− | local attackType = 'Normal' |
||
− | local attack = nil |
||
− | local attackText = '' |
||
− | local space = ' ' |
||
− | local attackBiasText = '' |
||
− | |||
− | if weapName == nil then return nil end |
||
− | |||
− | local Weapon = nil |
||
− | local cAvailability = false |
||
− | if conclave then |
||
− | Weapon = p.getConclaveWeapon(weapName) |
||
− | if Weapon ~= nil then |
||
− | cAvailability = getValue(Weapon, "Conclave", true, false, false) |
||
− | end |
||
− | if not cAvailability then Weapon = p.getWeapon(weapName) end |
||
− | else |
||
− | Weapon = p.getWeapon(weapName) |
||
− | end |
||
− | |||
− | local conclaveNotice = '' |
||
− | if conclave and cAvailability == false then |
||
− | conclaveNotice = |
||
− | '\n{| class="Data" style="font-size:10px; white-space:normal;"\n|-\n|Note: Non disponible en Conclave, displaying Cooperative stats and Cooperative Link.\n|}' |
||
− | end |
||
− | |||
− | if Weapon == nil then |
||
− | return 'L\'arme ' .. weapName .. ' n\'a pas été trouvée.' |
||
− | end |
||
− | |||
− | local function Value(valueName, asString, forTable, giveDefault) |
||
− | -- note that the three last parameters aren't in the same order in functions "Value" and "getValue" |
||
− | if (asString == nil) then asString = false end |
||
− | if (forTable == nil) then forTable = false end |
||
− | if (giveDefault == nil) then giveDefault = true end |
||
− | return getValue(Weapon, valueName, giveDefault, asString, forTable) |
||
− | end |
||
− | |||
− | local function whitePols(valueName) |
||
− | local pols = Value(valueName) |
||
− | local polIcon = '' |
||
− | |||
− | if type(pols) == "table" then |
||
− | local i = 0 |
||
− | if pols[1] == nil then |
||
− | polIcon = 'Aucune' |
||
− | return polIcon |
||
− | else |
||
− | while pols[i + 1] ~= nil do i = i + 1 end |
||
− | for j = 1, i do |
||
− | polIcon = polIcon .. Icon._Pol(pols[j], 'white', 'x16') |
||
− | end |
||
− | return polIcon |
||
− | end |
||
− | elseif pols ~= nil and type(pols) == "string" and pols ~= "Aucune" then |
||
− | return Icon._Pol(pols, 'white', 'x16') |
||
− | end |
||
− | return 'Aucune' |
||
− | end |
||
− | |||
− | -- for weapons which have no max ammo |
||
− | local ammoException = nil |
||
− | if Value("MaxAmmo") == nil then ammoException = true end |
||
− | |||
− | local isMelee = p.isMelee(Weapon) == "yes" |
||
− | |||
− | 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 |
||
− | |||
− | 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', 'x16') .. space .. |
||
− | dmg |
||
− | count = count + 1 |
||
− | else |
||
− | attackText = attackText .. '|| style=\"padding-right:4px;\" |' .. |
||
− | Icon._Proc(type, '', 'white', 'x16') .. space .. |
||
− | dmg |
||
− | end |
||
− | end |
||
− | |||
− | if (hasMultipleTypes(attack)) then |
||
− | attackBiasText = '\n| colspan=4 |' .. GetDamageString(attack, nil) .. |
||
− | " (" .. |
||
− | GetDamageBiasString(attack, nil, '', nil, 'white', |
||
− | 'x16') .. ")" |
||
− | end |
||
− | |||
− | local mRankIcon = '' |
||
− | local mRank = Value("Mastery", false, false, false) |
||
− | local mRankIconLoc = 'top:4px; left:9.5px;' |
||
− | if mRank then |
||
− | if string.len(mRank) >= 2 then |
||
− | mRankIconLoc = 'top:4px; left:5px;' |
||
− | end |
||
− | mRankIcon = |
||
− | '<div style="position:absolute;top:6px; left:4px; color:white; font-size:16px; font-weight:bold; text-shadow: 0 0 1px #0D1B1C, 0 0 4px #0D1B1C, 1px 1px 2px #0D1B1C, -1px 1px 2px #0D1B1C, 1px -1px 2px #0D1B1C, -1px -1px 2px #0D1B1C;">[[File:MasteryAffinity64.png|28px]]<div style="position:absolute;' .. |
||
− | mRankIconLoc .. '">' .. mRank .. '</div></div>' |
||
− | end |
||
− | |||
− | local dispoIcon = '' |
||
− | local dispoVal = Value("Disposition5", false, false, false) |
||
− | if dispoVal then |
||
− | dispoIcon = |
||
− | '<div style="position:absolute;top:6px; right:4px; color:white; font-size:16px; font-weight:bold; text-shadow: 0 0 1px #0D1B1C, 0 0 4px #0D1B1C, 1px 1px 2px #0D1B1C, -1px 1px 2px #0D1B1C, 1px -1px 2px #0D1B1C, -1px -1px 2px #0D1B1C;">[[File:RivenIcon64.png|28px]]<div style="position:absolute;top:3.5px; right:9.5px;">' .. |
||
− | dispoVal .. '</div></div>' |
||
− | end |
||
− | |||
− | if isMelee == true then |
||
− | A2Name = 'Type' |
||
− | A2Value = 'Class' |
||
− | C1Name = 'Vitesse Atq.' |
||
− | C1Value = 'FireRate' |
||
− | C1Toggle = true |
||
− | C2Name = 'Atq. Glissade' |
||
− | C2Value = 'SlideAttack' |
||
− | D1Name = 'Polarités' |
||
− | D1Value = 'Polarities' |
||
− | D1Value2 = 'StancePolarity' |
||
− | else |
||
− | A2Name = 'Tir' |
||
− | A2Value = 'Trigger' |
||
− | if hasCharged == true then |
||
− | C1Name = 'Charge Time' |
||
− | if weapName == "Staticor" then |
||
− | C1Value = {'Area', 'ChargeTime'} |
||
− | else |
||
− | C1Value = {'Charge', 'ChargeTime'} |
||
− | end |
||
− | C1Toggle = true |
||
− | else |
||
− | C1Name = 'Cad. de Tir' |
||
− | C1Value = 'FireRate' |
||
− | end |
||
− | C2Name = 'Sonorité' |
||
− | C2Value = 'NoiseLevel' |
||
− | D1Name = 'Polarités' |
||
− | D1Value = 'Polarities' |
||
− | end |
||
− | |||
− | local function Link(linkName) |
||
− | local spanStart = '<span class=\"LinkText\">' |
||
− | local spanEnd = '</span>' |
||
− | 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 Type = '' |
||
− | local tType = Value("Type") |
||
− | if tType == "Arch-Gun (Atmosphere)" then |
||
− | Type = "Arch-Gun (Atmo)" |
||
− | else |
||
− | Type = tType |
||
− | end |
||
− | |||
− | local image = |
||
− | '\n| class=\"Image\" style=\"height:120px;\" | <div style="position:relative; z-index:2;">[[File:' .. |
||
− | Value("Image") .. '|160px]]</div>' |
||
− | |||
− | -- creating the table |
||
− | local result = '<div style="position:relative;">\n{| class=\"Sub\"' .. |
||
− | newRow .. image .. mRankIcon .. dispoIcon .. newRow .. |
||
− | spacer .. newRow .. zeroPadding |
||
− | result = result .. dataText .. newRow |
||
− | result = |
||
− | result .. halfTable .. Link("Slot") .. space .. 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("Critique") .. space .. |
||
− | Value("CritChance", true) .. ' | ' .. |
||
− | Value("CritMultiplier", true) .. halfTable .. Link("Statut") .. |
||
− | 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 Weapon.Type ~= "Gear" then |
||
− | result = result .. newRow .. halfTable .. Link("Recharge") .. space .. |
||
− | Value("Reload", true, true) .. halfTable .. |
||
− | Link("Munitions") .. space .. Value("Magazine") |
||
− | -- if has max ammo => add max ammo stat |
||
− | if ammoException == nil then |
||
− | result = result .. ' / ' .. Value("MaxAmmo") |
||
− | end |
||
− | result = result .. newRow .. |
||
− | '\n| style=\"text-align:center;\" colspan=2 |' .. |
||
− | Link(D1Name) .. space .. whitePols(D1Value) |
||
− | elseif isMelee then |
||
− | result = result .. newRow .. |
||
− | '\n| style=\"text-align:center;\" colspan=2 |' .. |
||
− | Link(D1Name) .. space .. whitePols(D1Value2) .. ' | ' .. |
||
− | whitePols(D1Value) |
||
− | end |
||
− | result = result .. tableEnd .. conclaveNotice .. tableEnd .. '\n</div>' |
||
− | |||
− | return result |
||
− | end |
||
− | |||
− | function p.getWeaponReplaceList(frame) |
||
− | -- local Type = frame.args ~= nil and frame.args[1] or frame |
||
− | local fullList = {} |
||
− | local primaries = {} |
||
− | local secondaries = {} |
||
− | local melees = {} |
||
− | local archGuns = {} |
||
− | local archMelees = {} |
||
− | local theRest = {} |
||
− | |||
− | local avoidNames = { |
||
− | 'Lame Exaltée (Umbra)', 'Corvas (Atmosphere)', 'Cyngas (Atmosphere)', |
||
− | 'Dargyn', 'Doubles Decurion (Atmosphere)', 'Fluctus (Atmosphere)', |
||
− | 'Grattler (Atmosphere)', 'Imperator (Atmosphere)', |
||
− | 'Imperator Vandal (Atmosphere)', 'Phaedra (Atmosphere)', 'Rampart', |
||
− | 'Velocitus (Atmosphere)' |
||
− | } |
||
− | |||
− | local function addToList(name, link, list) |
||
− | if link == nil then link = name end |
||
− | -- local 6s = ' ' |
||
− | -- local 8s = ' ' |
||
− | local temp = ' <Replacement>\n <Find>[[' .. link .. |
||
− | ']]</Find>\n <Replace>{{Weapon|' .. name .. |
||
− | '}}</Replace>\n <Comment />\n <IsRegex>false</IsRegex>\n <Enabled>true</Enabled>\n <Minor>false</Minor>\n <BeforeOrAfter>false</BeforeOrAfter>\n <RegularExpressionOptions>IgnoreCase</RegularExpressionOptions>\n </Replacement>' |
||
− | return table.insert(list, temp) |
||
− | end |
||
− | |||
− | for i, val in Shared.skpairs(WeaponData["Weapons"]) do |
||
− | if not Shared.contains(avoidNames, val.Name) then |
||
− | |||
− | if val.Type == "Principale" then |
||
− | addToList(val.Name, val.Link, primaries) |
||
− | elseif val.Type == "Secondaire" then |
||
− | addToList(val.Name, val.Link, secondaries) |
||
− | elseif val.Type == "Mêlée" then |
||
− | addToList(val.Name, val.Link, melees) |
||
− | elseif val.Type == "Arch-Fusil" then |
||
− | addToList(val.Name, val.Link, archGuns) |
||
− | elseif val.Type == "Arch-Mêlée" then |
||
− | addToList(val.Name, val.Link, archMelees) |
||
− | else |
||
− | addToList(val.Name, val.Link, theRest) |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | table.insert(fullList, table.concat(primaries, '\n')) |
||
− | table.insert(fullList, table.concat(secondaries, '\n')) |
||
− | table.insert(fullList, table.concat(melees, '\n')) |
||
− | table.insert(fullList, table.concat(archGuns, '\n')) |
||
− | table.insert(fullList, table.concat(archMelees, '\n')) |
||
− | table.insert(fullList, table.concat(theRest, '\n')) |
||
− | |||
− | return table.concat(fullList, "\n") |
||
− | end |
||
− | |||
− | local function buildHTMLTable(table) |
||
− | local resultTable = '\n{| class="wikitable"' |
||
− | for i, val in Shared.skpairs(table) do |
||
− | resultTable = resultTable .. '\n|' .. i .. '||' |
||
− | if (val ~= nil and type(val) == "table") then |
||
− | resultTable = resultTable .. buildHTMLTable(val) |
||
− | else |
||
− | resultTable = resultTable .. tostring(val) |
||
− | end |
||
− | resultTable = resultTable .. '\n|-' |
||
− | end |
||
− | resultTable = resultTable .. '\n|}' |
||
− | return resultTable |
||
− | end |
||
− | |||
− | function p.buildHTMLDB() return buildHTMLTable(WeaponData["Weapons"]) end |
||
− | |||
− | local function buildFamilyMap(weapArray) |
||
− | |||
− | local ret = {} |
||
− | |||
− | for _, weapon in ipairs(weapArray) do |
||
− | local key = nil |
||
− | if (weapon.Family ~= nil) then |
||
− | key = weapon.Family |
||
− | else |
||
− | key = weapon.Name |
||
− | end |
||
− | if (ret[key] == nil) then |
||
− | ret[key] = {weapon.Name} |
||
− | else |
||
− | table.insert(ret[key], weapon.Name) |
||
− | end |
||
− | end |
||
− | |||
− | return ret |
||
− | end |
||
− | |||
− | local function printFamily(familyName, familyValues, conclave) |
||
− | |||
− | local ret = {} |
||
− | local ttType = 'Weapon' |
||
− | |||
− | table.insert(ret, |
||
− | Tooltip._tooltipText(familyName, ttType, nil, conclave, nil)) |
||
− | |||
− | local famString = {} |
||
− | if (#familyValues > 1) then |
||
− | for _, wpName in pairs(familyValues) do |
||
− | if (wpName ~= familyName) then |
||
− | local newName = Shared.trim(wpName:gsub(familyName, "")) |
||
− | -- Special cases |
||
− | if (newName == "MK1-") then |
||
− | newName = "MK1" |
||
− | elseif (Shared.contains(newName, "Dex ")) then |
||
− | newName = "Dex" |
||
− | end |
||
− | |||
− | table.insert(famString, Tooltip._tooltipText(wpName, ttType, |
||
− | newName, conclave, |
||
− | nil)) |
||
− | end |
||
− | end |
||
− | |||
− | table.insert(ret, |
||
− | '(' .. table.concat(famString, Shared.getListSep()) .. ')') |
||
− | end |
||
− | |||
− | return table.concat(ret, ' ') |
||
− | end |
||
− | |||
− | function p.getWeaponsList(frame) |
||
− | |||
− | local mainCat = frame.args ~= nil and frame.args[1] |
||
− | local subCat = frame.args ~= nil and frame.args[2] |
||
− | local triggerType = frame.args ~= nil and frame.args[3] |
||
− | local conclave = frame.args ~= nil and frame.args[4] |
||
− | conclave = conclave ~= nil and conclave ~= "false" |
||
− | |||
− | return p._getWeaponsList(mainCat, subCat, triggerType, conclave) |
||
− | end |
||
− | |||
− | function p._getWeaponsList(mainCat, subCat, triggerType, conclave) |
||
− | |||
− | local testFunction = nil |
||
− | if (mainCat == "Mêlée") then |
||
− | testFunction = function(x) |
||
− | return weaponFilter_Melee(x, mainCat, subCat) |
||
− | end |
||
− | else |
||
− | testFunction = function(x) |
||
− | return weaponFilter_NonMelee(x, mainCat, subCat, triggerType) |
||
− | end |
||
− | end |
||
− | -- Get array of weapons |
||
− | local weapArray = nil |
||
− | if (conclave) then |
||
− | weapArray = p.getConclaveWeapons(testFunction) |
||
− | else |
||
− | weapArray = p.getWeapons(testFunction) |
||
− | end |
||
− | -- Build family map |
||
− | local weapMap = buildFamilyMap(weapArray) |
||
− | -- Build String for result array |
||
− | local ret = {} |
||
− | for family, wpList in Shared.skpairs(weapMap) do |
||
− | if (Shared.contains(wpList, family, true)) then |
||
− | table.insert(ret, printFamily(family, wpList, conclave)) |
||
− | else |
||
− | for _, tmpName in pairs(wpList) do |
||
− | table.insert(ret, Tooltip._tooltipText(tmpName, 'Weapon', nil, |
||
− | conclave, nil)) |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | return table.concat(ret, Shared.getListSep()) |
||
− | end |
||
− | |||
− | local function getAbilityWeaponArray(abilityName) |
||
− | |||
− | local ret = WeaponData["AbilityWeapons"][abilityName] |
||
− | if (ret == nil) then ret = {} end |
||
− | |||
− | return ret |
||
− | end |
||
− | |||
− | function p.buildAbilityWeaponTab(frame) |
||
− | |||
− | local abilityName = frame.args[1] |
||
− | local ret = {} |
||
− | local left = true |
||
− | |||
− | local wpArray = getAbilityWeaponArray(abilityName) |
||
− | for _, wpName in pairs(wpArray) do |
||
− | table.insert(ret, '[[File:') |
||
− | table.insert(ret, getValue(p.getWeapon(wpName), "IMAGE")) |
||
− | table.insert(ret, '|200px|') |
||
− | if (left) then |
||
− | left = false |
||
− | table.insert(ret, 'left]]') |
||
− | else |
||
− | left = true |
||
− | table.insert(ret, 'right]]') |
||
− | end |
||
− | local pageName = p._getLink(wpName) |
||
− | table.insert(ret, frame:preprocess('{{main|' .. pageName .. '}}')) |
||
− | local introSection = frame:expandTemplate{ |
||
− | title = 'fetchSection', |
||
− | args = {pageName, 'intro'} |
||
− | } |
||
− | if (introSection == nil or introSection == '') then |
||
− | introSection = "L'article [[" .. pageName .. |
||
− | "]] ne possède pas de section intro." |
||
− | end |
||
− | table.insert(ret, '<br/>') |
||
− | table.insert(ret, introSection) |
||
− | table.insert(ret, frame:expandTemplate{title = 'clr'}) |
||
− | end |
||
− | return |
+ | return frame:preprocess(tostring(signWpsTable)) |
end |
end |
||
Dernière version du 1 avril 2024 à 10:27
Weapons contient toutes les Armes de WARFRAME.
Usage
Template
In template and articles: {{#invoke:Weapons|function|input1|input2|...}}
Documentation
Objets du paquet
weapons._isVariant(weaponName)
(function)- Checks if a weapon is a variant or not.
- Paramètre:
weaponName
Weapon name (string) - Retours:
- True if weapon is a variant, false otherwise (boolean)
- Weapon's variant name or "Base" if weapon is not a variant (string)
- Weapon name, same as weaponName (string)
weapons._buildName(baseName, variant)
(function)- Builds the full name of a weapon's variant. Does not check if it exists or not.
- Paramètres:
baseName
Weapon's base name (e.g. "Braton") (string)variant
Variant name (e.g. "Vandal"); if nil, returns base weapon name instead (string; optionnel)
- Retours: Weapon's variant name (e.g. "Braton Vandal") (string)
weapons._getWeapon(weaponName, pvp)
(function)- Returns a specific weapon table entry from
/data
or/Conclave/data
. - Paramètres:
weaponName
Weapon name (string)pvp
If true, gets PvP stats of weapon instead, false otherwise; defaults to false (boolean; optionnel)
- Retours: Weapon table (table)
weapons._getValue(Weapon, key, attack)
(function)- Gets the raw value of a certain statistic of a weapon.
- Paramètres:
Weapon
Weapon table (table)key
Name of key (string)attack
Name of attack to search through; defaults to 'Attack1' or what '_TooltipAttackDisplay' is set to (string; optionnel)
- Retours: Value of statistic (string, number)
weapons._getFormattedValue(Weapon, keyName, attackName)
(function)- Gets the formatted value of a certain statistic of a weapon to be displayed the wiki.
- Paramètres:
Weapon
Weapon table (table)keyName
Name of key (string)attackName
Name of attack to search through; defaults to 'Attack1' (string; optionnel)
- Retours: Value of statistic (string)
weapons._statReader(weap, atk)
(function)- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair.
- Paramètres:
weap
Weapon entry (table)atk
Attacks table index or Attack entry (number|table)
- Retours: Getter function (function)
weapons._statFormatter(weap, atk)
(function)- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair.
- Paramètres:
weap
Weapon entry (table)atk
Attacks table index or Attack entry (number|table)
- Retours: Getter function (function)
weapons._getWeapons(validateFunction, source, ignoreIgnore, sortFunc)
(function)- Returns a subset of
/data
or/Conclave/data
based on a validation function. - Paramètres:
validateFunction
Function that filters out a weapon by taking in a Weapon table argument (function)source
Name of weapon entry to use (string; optionnel)ignoreIgnore
If true, ignores the _IgnoreEntry flag, false otherwise; defaults to false (boolean; optionnel)sortFunc
Custom comparison function; false -> no sorting; defaults to sorting in ascending order by weapon name (function; optionnel)
- Retours: Table of weapon table entries as seen in
/data
(table) weapons._getMeleeWeapons(weapType, pvp)
(function)- Returns all melee weapons. If weapType is not nil, only grab for a specific type For example, if weapType is "Nikana", only pull Nikanas.
- Paramètres:
weapType
(boolean; optionnel)pvp
If true, only gets melee weapons available in Conclave, false otherwise; defaults to false (boolean; optionnel)
- Retours: An array of melee weapon table entries as seen in
/data
(table) weapons.getValue(weap, atk, k)
(function)- Main frame invokable function to access any raw/computed attribute/column/key of a weapon entry. See default table in M:Weapons to see all valid computed attributes.
- Paramètres:
weap
Weapon name in EN locale (string)atk
Attacks table index (number)k
Key name (string)
- Retours: Raw or computed value associated with k key
weapons.getFormattedValue(weap, atk, k)
(function)- Main frame invokable function to access any formatted attribute/column/key of a weapon entry. See default table in M:Weapons to see all valid computed attributes.
- Paramètres:
weap
Weapon name in EN locale (string)atk
Attacks table index (number)k
Key name (string)
- Retours: Formatted value associated with k key
weapons.getMeleeWeaponGallery(frame)
(function)- Builds a melee weapon gallery as seen on Template:MeleeCategory.
- Paramètre:
frame
Frame object w/ first argumenting being string meleeClass (table) - Retours: Resultant wikitext of gallery (string)
weapons.getWeaponCount(frame)
(function)- Gets the total count of weapons as used on Mastery Rank#Total Mastery.
- Paramètre:
frame
Frame object w/ the first argument being the weaponSlot and the second argument being a boolean to getFullList (table) - Retours:
- Total count of weapons in a certain category/type (number)
- List of weapon names that count for mastery in a particular weapon slot (table)
weapons.getWeaponCount(frame)
(function)- Gets the total count of weapons as used on Mastery Rank#Total Mastery.
- Paramètre:
frame
Frame object w/ the first argument being the weapon slot (table) - Retours: Total number of weapons that can reward Mastery XP (number)
weapons.getPolarityTable(frame)
(function)- Builds wikitable of all weapons' innate polarities as seen on Polarity.
- Paramètre:
frame
Frame object (table) - Retours: Wikitext of resultant wikitable (string)
weapons.buildDamageTypeTable(frame)
(function)- Builds a table that lists out all weapons with a certain damage type
- Paramètre:
frame
Frame object (table) - Retours: Wikitext of resultant wikitable (string)
weapons._shortLinkList(Weapon, tooltip)
(function)- Builds a list of weapons, with variants being next to base weapon name inside parentheses (e. g. Braton ( MK1, Prime)).
- Paramètres:
Weapon
Weapon table (table)tooltip
If true, adds weapon tooltips, false otherwise; defaults to false (boolean)
- Retours: Wikitext of resultant list (string)
weapons.getMasteryShortList(frame)
(function)- Builds a list of weapons' mastery requirements as seen on Template:EquipmentUnlock, Template:EquipmentUnlock/Primary, Template:EquipmentUnlock/Secondary, Template:EquipmentUnlock/Melee, etc.
- Paramètre:
frame
Frame object w/ first argument being a string weaponSlot (table) - Retours: Wikitext of resultant list (string)
weapons.getConclaveList(frame)
(function)- Builds a list of PvP weapons as seen on PvP#Limitations.
- Paramètre:
frame
Frame object w/ first argument being a string weaponSlot (table) - Retours: Wikitext of resultant list (string)
weapons.getRivenDispositionTable(frame)
(function)- Builds a disposition wikitable as seen on Riven Mods/Weapon Dispos.
- Paramètre:
frame
Frame object w/ first argument being a string weaponSlot (table) - Retours: Wikitext of resultant wikitable (string)
weapons.buildAbilityWeaponTab()
(function)- Builds a simple div in the Weapon part of the abilities if an Exalted Weapon is existing.
- Retours: with weapLink, main page link, weapImg, introSection, fetched from the main Weapon page
- Documentation automatique créée à l'aide de Docbuntu (-> Modèle automatique)
Voir aussi
- Weapons/Conclave/data
- Weapons/Conclave/data/doc
- Weapons/Conclave/data/melee
- Weapons/Conclave/data/melee/doc
- Weapons/Conclave/data/principale
- Weapons/Conclave/data/principale/doc
- Weapons/Conclave/data/secondaire
- Weapons/Conclave/data/secondaire/doc
- Weapons/characteristics
- Weapons/characteristics/doc
- Weapons/compare
- Weapons/comptable
- Weapons/data
- Weapons/data/archwing
- Weapons/data/autres
- Weapons/data/compagnon
- Weapons/data/doc
- Weapons/data/melee
- Weapons/data/melee/doc
- Weapons/data/modulaire
- Weapons/data/principale
- Weapons/data/principale/doc
- Weapons/data/railjack
- Weapons/data/secondaire
- Weapons/data/secondaire/doc
- Weapons/data/validate
- Weapons/data/validate/doc
- Weapons/doc
- Weapons/infobox
- Weapons/infobox/doc
- Weapons/nav
- Weapons/ppdata
- Weapons/ppdata/doc
- Weapons/preprocess
- Weapons/preprocess/doc
- Weapons/testcases
- Weapons/testcases/doc
Modules and Lua Libraries Standard Libraries (STL) Inclusions Scribunto (optional bit32 & libraryUtil) Extensions M:Math • M:String • M:Table Base de données Général M:Codex (/data) • M:Companions (/data) • M:Conservation (/data) • M:DamageTypes (/data) • M:DojoRoom/data • M:Ennemis (/data) • M:Factions/data • M:FactionScript (/data) • M:GuaranteedRewards/data • M:Icon (/data) • M:Keys/data • M:KeyBindings (/data) • M:Missions (/data) • M:Music/data • M:Upgrades/data • M:Version (/data) Warframes M:Ability (/data) • M:Maximization (/data) • M:Warframes (/data) Armes M:Modular (/data) • M:Weapons (/data, /ppdata) Améliorations M:Arcane (/data) • M:Decrets (/data) • M:Focus (/data) • M:Mods (/data) • M:Stances (/data) Tables de Drop M:Acquisition (/data) • M:DropTables (/data) • M:Void (/data) Marchands M:Baro (/data) • M:Marchands (/data) Fabrication M:Blueprints/data • M:Research (/data) • M:Resources (/data) Cosmétiques M:Decorations (/data) • M:Cosmetics/data • M:Sigils/data • M:TennoGen (/data) Infoboxes M:Arcane/infobox • M:Conservation/infobox • M:Ennemi/infobox • M:Missions/infobox • M:Mods/infobox • M:Resources/infobox • M:Void/page • M:Warframes/infobox • M:Weapons/infobox Wiki Dev Wiki Fork Module:Common (/i18n) • M:Docbunto (/cli, /i18n) • M:Entrypoint • M:I18n • M:Infobox (/i18n) • M:LanguageList • M:Mbox (/i18n) • M:ModuleTest • M:Reference • M:ReleaseStatus (/i18n) • M:TestHarness (/i18n) • M:WDSButton (/data) Wikipedia Fork M:Arguments (/i18n) • M:FallbackList • M:Yesno Third-Party Fork M:Codec • M:CSV • M:Date • M:Inspect • M:JSON • M:Lexer • M:LuaClassSystem • M:LuaSerializer • M:Navbox • M:Navigation • M:Unindent Wiki-Unique M:Database • M:DatastoreManifest • M:Delay • M:DependencyGraph • M:InfoboxBuilder • M:Lua • M:Map • M:Placeholder • M:RemoveCategory • M:StatObject • M:Tooltips Autres M:Cost • M:Enum/data • M:InternalNames • M:MasteryRank • M:Polarity • M:Sandbox • M:WarframeUsageData2020/data Archivés/Dépréciés M:Avionics (/data) • M:BuildRequire • M:FormatingTool • M:Gallery • M:NightwaveActs • M:Shared • M:Syndicates/data • M:TennoScript • M:TranslationExamples • M:VoidByReward • M:WorldState (/data) Bug Reports • Development Guide • Localization Guide (L10n Message Data Stores) • Programming Standards • Projects & Current Backlog • Updating Databases • Full Module List • Lua Reference Manual Code
--- '''Weapons''' contient toutes les [[Armes]] de [[WARFRAME]].
--
-- @module weapons
-- @alias p
-- @attribution [[User:Cephalon Scientia|Cephalon Scientia]]
-- @attribution [[User:FINNER|FINNER]]
-- @attribution [[User:Falterfire|Falterfire]]
-- @attribution [[User:Gigamicro|Gigamicro]]
-- @attribution [[User:Flaicher|Flaicher]]
-- @attribution [[User:Synthtech|Synthtech]]
-- @attribution [[User:Yazuh|Yazu]] (retranscription)
-- @image IconPrimaryWeaponRifle.png
-- @require [[Module:StatObject]]
-- @require [[Module:DamageTypes]]
-- @require [[Module:Polarity]]
-- @require [[Module:Math]]
-- @require [[Module:Table]]
-- @require [[Module:Tooltips]]
-- @require [[Module:Version]]
-- @require [[Module:Stances/data]]
-- @require [[Module:Weapons/data]]
-- @require [[Module:Weapons/Conclave/data]]
-- @release stable
-- <nowiki>
-- TODO: Add LuaDoc style comments to new functions
local p = {}
local Delay = require([[Module:Delay]])
local WeaponData = Delay.require([[Module:Weapons/data]])
local ConclaveData = Delay.require([[Module:Weapons/Conclave/data]])
local Tooltip = Delay.require([[Module:Tooltips]]) -- full, icon
local Version = Delay.require([[Module:Version]]) -- _getVersion, _getVersionDate
local Polarity = Delay.require([[Module:Polarity]]) -- _pols, _polarity
local Math = Delay.require([[Module:Math]]) -- formatnum
local Table = Delay.require([[Module:Table]]) -- size, skpairs
local iterationOrderArray = require([[Module:DamageTypes]]).iterationOrderArray
-- TODO: Should decouple from localized names for internationalization
local VARIANT_LIST = {
"Prime", "Prisma", "Wraith", "Vandal", "Vaykor", "Synoid", "Telos", "Secura",
"Sancti", "Rakta", "Mara", "Carmine", "Ceti", "Dex", "MK1", "Kuva", "Principe"
}
table.unpack = table.unpack or unpack
local StatObject = require [[Module:StatObject]]
p.__StatObject = StatObject
local statRead = StatObject.statRead
local statFormat = StatObject.statFormat
local indexes = StatObject.meta.indexes
local ors = StatObject.meta.ors
local unpacks = StatObject.meta.unpacks
local passes = StatObject.meta.passes
local percent = StatObject.meta.percent
local percents = StatObject.meta.percents
--- Gets the attack entry from weapon entry.
-- @function p._getAttack
-- @param {table} weap Weapon entry
-- @param[opt] {number|table} atk Attacks table index or Attack entry
-- @return {table} A single weapon+attack struct
local function getWeaponAttack(weap, atk)
if type(atk) == 'number' then return StatObject.getStruct2(weap,weap.Attacks[atk]) end
if weap.AttackName then return weap end
if type(atk) == 'table' then return StatObject.getStruct2(weap,atk) end
local key = atk or weap['_TooltipAttackDisplay'] or 1
if weap.Attacks == nil then
error('p._getWeaponAttack(weap, atk): Attacks table is nil in '..mw.dumpObject(weap))
end
return StatObject.getStruct2(weap,weap.Attacks[key])
end
p._getAttack = getWeaponAttack
p._getWeaponAttack = getWeaponAttack
function p._statRead(w, a, ...)
return statRead(getWeaponAttack(w, a), ...)
end
function p._statFormat(w, a, ...)
return statFormat(getWeaponAttack(w, a), ...)
end
function p.stat(frame)
return p._statFormat(p._getWeapon(frame.args[1] or 'Skana Prime'), nil, frame.args[2] or 'Name')
end
-- Wrapper function for use in StatObject
local function dmgTooltip(damageType)
return Tooltip.full(damageType, 'DamageTypes')
end
-- Defining getters/attributes whose names match the associated database key or some custom derived attribute.
-- Index key will be name of getter function and can be mapped to a single value (getter definition)
-- or a table with two values (getter and format function definitions)
-- Cheatsheet on adding new keys:
-- StatName = default value -> Get raw value with the same StatName from M:Weapons/data and with no additional formatting (aka default formatting)
-- StatName = function(self) return self.StatName + 1 end -> Define custom getter function and use default formatting
-- StatName = { default value, '%.2f' } -> Get raw value value with same StatName from M:Weapons/data and use format string for formatting
-- StatName = { function(self) return ... end, '%.2f' } -> Define custom getter function and use format string for formatting
-- StatName = { function(self) return ... end, function(self, returnValue1, returnValue2, ...) return tostring(returnValue) end } - > Define custom getter and format functions
-- (Note that format function will pass in return value(s) from getter as well as object self)
-- TODO: Put StatObject keys in alphabetical order for navigation
StatObject.default = {
AttackName = 'Normal Attack',
AmmoCost = nil,
AmmoPickup = function(weapAtk)
return weapAtk['AmmoPickup'] or
weapAtk['Slot'] == 'Principale' and 80 or
weapAtk['Slot'] == 'Secondaire' and 40 or
weapAtk['Slot'] == 'Arch-Fusil (Atmosphère)' and 1000 or
0
end,
DamageBias = {
function(weapAtk)
if not weapAtk.Damage then
error('DamageBias: no Attack.Damage')
return 0, 0, 0
end
local total, bestdmg, bestdt = 0, 0, nil
for dt, dmg in pairs(weapAtk.Damage) do
local dmg = dmg
if dmg >= bestdmg then
bestdmg, bestdt = dmg, dt
end
total = total + dmg
end
return StatObject.ucacheIn(weapAtk, 'DamageBias', { bestdmg / total, bestdt, total })
end,
{ percent, passes(dmgTooltip), '' }
},
BiasPortion = { indexes('DamageBias', 1), percent },
BiasType = { indexes('DamageBias', 2), function(self, biasType) return Tooltip.icon(biasType, 'DamageTypes') end },
BaseDamage = { indexes('DamageBias', 3), '%.2f' },
-- More precise damage values to 4 decimal places for PvP since PvP damage is calculated
-- based on a floating-point scalar. Damage quantization is more relevant in PvP so more
-- precise numbers needed.
PvPBaseDamage = { indexes('DamageBias', 3), '%.4f' },
TotalDamage = { function(weapAtk)
return statRead(weapAtk, 'BaseDamage') * statRead(weapAtk, 'Multishot')
end, passes(Math.formatnum)
},
-- Including max +60% Progenitor bonus for Kuva/Tenet weapons
TotalDamageWithProgenBonus = { function(weapAtk)
return statRead(weapAtk, 'TotalDamage') * (statRead(weapAtk, 'IsLichWeapon') and 1.6 or 1)
end, passes(Math.formatnum)
},
ChargeTime = { 0, '%.1f s' },
ExplosionDelay = { 0, '%.1f s' },
ExtraHeadshotDmg = { 0, percents('+%.2f%%') },
Falloff = {
function(weapAtk)
local fo = weapAtk['Falloff'] or {}
return fo.StartRange or 0, fo.EndRange or math.huge, 1 - (fo.Reduction or 1)
end,
{ '%.1f m (100%%) -', '%.1f m', percents('(%.2f%%)') }
},
FalloffStart = { indexes('Falloff', 1), '%.1f m' },
FalloffEnd = { indexes('Falloff', 2), '%.1f m' },
-- Damage reduction from falloff instead of damage multiplier
FalloffReduction = { function(weapAtk)
local _, _, falloff = statRead(weapAtk, 'Falloff')
return 1 - falloff
end, percent
},
FalloffRate = { function(weapAtk)
local startdist,enddist,endpercent = statRead(weapAtk, 'Falloff')
return -(enddist-startdist)/(endpercent-1)
end, '%.1fm/%%'
},
HeadshotMultiplier = { 1, '%.1fx' },
Multishot = 1,
PunchThrough = { 0, '%.1f m' },
ShotSpeed = { nil, function(self, shotSpeed)
if shotSpeed == nil or "?" then
return 'N/A'
end
return ('%.1f m/s'):format(shotSpeed)
end
},
BurstDelay = { 0, '%.4f s' },
BurstReloadDelay = { 0, '%.2f s' },
BurstsPerSec = { function(weapAtk)
-- There is no delay after last shot in burst
return 1 / ( (1 / statRead(weapAtk, 'FireRate') ) + statRead(weapAtk, 'BurstDelay') * ( statRead(weapAtk, 'BurstCount') - 1) )
end, '%.2f rafales/sec' },
CritChance = { 0, percent },
CritMultiplier = { 1, '%.2fx' },
ForcedProcs = { unpacks('ForcedProcs'), function(s, ...)
local procs = { ... }
if procs[1] == nil then
return 'Aucun statut forcé'
end
local result = {}
for _, proc in ipairs(procs) do
table.insert(result, Tooltip.full(proc, 'DamageTypes'))
end
return table.concat(result, ', ')
end
},
Radius = { 0, '%.1f m' },
StatusChance = { 0, percent },
Disposition = {
function(weap)
local d = weap['Disposition']
-- Returning a categorical bin value of 1, 2, 3, 4, or 5 based on where disposition value
-- is on the continuous scale of 0.5-1.55. If disposition value is nil then return 0
return d or 0, type(d)=='number' and math.floor(5*(d-.3+.009*(d<1 and 1 or -1))) or 0
end,
function(s, v, d)
return StatObject.default.Dispo[2](s, d)..(' (%.2fx)'):format(v)
end
},
Dispo = { indexes('Disposition', 2), function(s, d)
if d and d == d and d > 0 then
return ('●'):rep(math.min(d, 5))..('○'):rep(5 - d)
end
return '×××××' -- '●○×' --> E2978F E2978B C397
end },
Introduced = { function(weap)
return weap['Introduced'] and Version._getVersion(weap['Introduced'])['Name'] or 'N/A'
end, passes(Version._getVersionLink)
},
IntroducedDate = function(weap)
return weap['Introduced'] and Version._getVersionDate(weap['Introduced']) or 'N/A'
end,
IsLichWeapon = function(weap)
return weap['IsLichWeapon'] and true or false
end,
Mastery = 0,
Link = { nil, '[[%s]]' },
Name = { nil, function(s, v) return Tooltip.full(v, 'Weapons') end },
InternalName = '',
NameLink = { function(weap) return weap.Link, weap.Name end, '[[%s|%s]]' },
Polarities = { nil, passes(Polarity._pols) },
Traits = { unpacks('Traits'), { sep = ', ' } },
-- Default nil b/c some attacks don't have an associated accuracy/spread value (like AoE explosions)
Accuracy = { nil, function(self, value)
if (value == nil) then
return 'N/A'
end
return value
end
},
-- Inverse of accuracy. Spread of 1 equates to no spread.
-- Alternatively, it can be calculated by the average of min and max spread, see AvgSpread getter.
Spread = { function(weapAtk)
local accuracy = statRead(weapAtk, 'Accuracy')
return (accuracy == nil) and nil or 100 / accuracy
end, function(self, value)
if (value == nil) then
return 'N/A'
end
return value
end
},
AmmoType = function(weapAtk)
return weapAtk['AmmoType'] or ({
['Arch-Fusil (Atmosphère)'] = 'Lourde',
['Secondaire'] = 'Secondaire',
['Principale'] = 'Principale'
})[weapAtk['Slot']] or 'None'
end,
-- Not all weapons have an Exilus slot so default to nil
ExilusPolarity = { nil, function(self, exilusPolarity)
if (exilusPolarity == nil) then
return 'N/A'
end
return Polarity._polarity(exilusPolarity)
end
},
Magazine = 1,
AmmoMax = { function(weapAtk)
if statRead(weapAtk, 'IsMelee') then
return nil
end
return weapAtk['AmmoMax'] or math.huge
end, passes(Math.formatnum)
},
Range = { function(weapAtk)
return weapAtk['Range'] or statRead(weapAtk, 'ShotType') == 'Impact-direct' and 300 or 0
end, '%.1f m'
},
Reload = { ors('Reload', 'RechargeTime', 0), '%.2f s' },
RechargeTime = { function(weapAtk)
return statRead(weapAtk, 'ReloadStyle'):find'[Rr]egen' and statRead(weapAtk, 'Magazine') / statRead(weapAtk, 'ReloadRate') or nil
end, '%.2f s'
},
ReloadRate = { 0, '%.2f balles/sec' }, -- Used for rechargeable weapons; not necessarily inverse of reload time b/c of presence of reload delay
ReloadDelay = { function(weapAtk)
return weapAtk['ReloadDelay'] or 0
end, '%.2f s'
},
ReloadDelayEmpty = { ors('ReloadDelayEmpty', 'ReloadDelay'), '%.2f s' },
-- Reload speed will be calculated as the inverse of reload time for purposes
-- of keeping how we rank stats consistent for [[Module:Weapons/preprocess]]
-- (larger number = higher stat; a short reload time can be expressed as fast reload
-- speed which would be a larger value in magnitude)
ReloadSpeed = { function(weapAtk)
return 1 / statRead(weapAtk, 'Reload')
end, function(str, reloadSpeed)
return string.format('%.2f%% progression de recharge par seconde', reloadSpeed * 100)
end },
ReloadStyle = 'Magazine',
Spool = { 0, '%d balles' },
SpoolStartFireRate = { 0, '%.1fx' }, -- scalar that is applied to fire rate stat for auto-spool weapons
AvgSpread = { function(weapAtk)
local minSpread = statRead(weapAtk, 'MinSpread')
local maxSpread = statRead(weapAtk, 'MaxSpread')
if (minSpread == nil) then
return nil
end
return (minSpread + maxSpread) / 2
end, function(self, value)
if (value == nil) then
return 'N/A'
end
return ('%.2f°'):format(value)
end
},
-- Default nil b/c some attacks don't have an associated accuracy/spread value (like AoE explosions)
MinSpread = { nil, function(self, value)
if (value == nil) then
return 'N/A'
end
return ('%.2f°'):format(value)
end
},
MaxSpread = { nil, function(self, value)
if (value == nil) then
return 'N/A'
end
return ('%.2f°'):format(value)
end
},
Trigger = 'N/A',
BlockAngle = { 0, '%d°' },
ComboDur = { 0, '%.1f s' },
FollowThrough = { 0, '%.1fx' },
HeavyAttack = { 0, passes(Math.formatnum) },
HeavySlamAttack = { 0, passes(Math.formatnum) },
HeavyRadialDmg = { 0, passes(Math.formatnum) },
HeavySlamRadius = { 0, '%.1f m' },
MeleeRange = { 0, '%.2f m' },
SlamAttack = { 0, passes(Math.formatnum) },
SlamRadialDmg = { function(weapAtk)
return weapAtk.SlamRadialDmg or 0, statRead(weapAtk, 'SlamRadialElement')
end, function(self, dmg, elem)
if elem then
return Tooltip.icon(elem, 'DamageTypes')..' '..Math.formatnum(dmg)
end
return Math.formatnum(dmg)
end
},
SlamRadialElement = { nil, function(self, value)
return value ~= nil and Tooltip.full(value, 'DamageTypes') or 'Même répartition des types de dégâts que pour l\'attaque normale'
end
},
-- Slam radial forced proc(s)
SlamRadialProcs = { nil, function(self, proc)
if type(proc)=='table' then
local result = {}
for _, elem in ipairs(proc) do
table.insert(result, Tooltip.full(elem, 'DamageTypes'))
end
return table.concat(result, '<br />')
else
return 'N/A'
end
end
},
SlamRadius = { 0, '%.1f m' },
SlideAttack = { function(weapAtk)
return weapAtk.SlamRadialDmg or 0, statRead(weapAtk, 'SlideElement')
end, function(self, dmg, elem)
if elem then
return Tooltip.icon(elem, 'DamageTypes')..' '..Math.formatnum(dmg)
end
return Math.formatnum(dmg)
end
},
SlideElement = { nil, function(self, value)
return value ~= nil and Tooltip.full(value, 'DamageTypes') or 'Même répartition des types de dégâts que pour l\'attaque normale'
end
},
--[[Stances = function(weapAtk)
if not statRead(weapAtk, 'IsMelee') then return end
return Stances._getAllStancesSameType(statRead(weapAtk, "Class"))
-- ^ currently a local function
end,--]]
-- Not all weapons have an Stance slot so default to nil
StancePolarity = { nil, function(self, stancePolarity)
if (stancePolarity == nil) then
return 'N/A'
end
return Polarity._polarity(stancePolarity)
end
},
SweepRadius = { 0, '%.2f m' },
WindUp = { 0, '%.1f s' },
BurstCount = 1,
-- Average crit/proc count from a single attack input
AvgCritCount = function(weapAtk)
return statRead(weapAtk, 'CritChance') * statRead(weapAtk, 'Multishot')
end,
AvgCritPerSec = function(weapAtk)
return statRead(weapAtk, 'AvgCritCount') * statRead(weapAtk, 'EffectiveFireRate')
end,
AvgProcCount = function(weapAtk)
return ( statRead(weapAtk, 'StatusChance') + Table.size(weapAtk['ForcedProcs'] or {}) ) * statRead(weapAtk, 'Multishot')
end,
AvgProcPerSec = function(weapAtk)
return statRead(weapAtk, 'AvgProcCount') * statRead(weapAtk, 'EffectiveFireRate')
end,
InterShotTime = function(weapAtk)
local v = statRead(weapAtk, 'Magazine') == 1 and statRead(weapAtk, 'Reload') + statRead(weapAtk, 'ReloadDelayEmpty') or 0
if v == 0 then v = 1 / statRead(weapAtk, 'FireRate') end
return v
end,
EffectiveFireRate = function(weapAtk)
return 1 / ( statRead(weapAtk, 'ChargeTime') + statRead(weapAtk, 'InterShotTime') )
end,
ShotsPerMag = function(weapAtk)
-- Default to 1 "ammo cost" even if attack does not directly consume ammo (e.g. AoE hits, speargun throws, etc.)
return math.floor(statRead(weapAtk, 'Magazine') / (statRead(weapAtk, 'AmmoCost') or 1))
end,
FireRate = { function(weapAtk)
local dataFireRate = weapAtk['FireRate']
if dataFireRate then return dataFireRate end
-- TODO: Think we can safely remove this calculation of FireRate from BurstFireRate, BurstDelay, and BurstCount
-- for burst-fire attacks since FireRate is also included for those
mw.log('calcul de la cadence de tir depuis les stats de rafales pour '..statRead(weapAtk, 'Name'))
local count = statRead(weapAtk, 'BurstCount')
local fireRate = count / (1 / statRead(weapAtk, 'BurstFireRate') + count * statRead(weapAtk, 'BurstDelay'))
return fireRate
end, '%.3f tirs/sec'
},
BurstFireRate = { function(weapAtk)
return 1 / statRead(weapAtk, 'BurstDelay')
end, '%.2f tirs/sec'
},
--[[
Describing what happens when a gun in WARFRAME is fired using player-made terminology:
A particular gun consumes a set number of ammo in order to fire a set number of shots
on a single player input for a particular attack.
A single player input is defined as:
* a single attack button press for semi-auto and burst trigger weapons
* the moment the next shot is being fired when the attack button is being held for automatic/held trigger weapons
* the action of holding the attack button for charge trigger weapons
* for duplex-fire trigger weapons, the hold and release of the attack button counts as two inputs
A shot is defined as the base unit of attack of a weapon when unmodded.
* A single attack input can launch several shots as in the case of burst-fire weapons.
* A single shot can shoot more than one projectile, affected by the multishot stat, as in the case of shotguns.
* A single shot can consume more than one unit of ammo (e.g. Tenora's alt-fire) or
less than one unit of ammo (e.g. Ignis and most continuous weapons).
A gun can have multiple attacks which can be triggered using different buttons
and/or types of button inputs (e.g. pressing vs. holding)
]]--
CalcDamage = function(weapAtk)
local weapon, attack = weapAtk, weapAtk
-- Count
-- How many shots are fired in a single player input
local tapShots = statRead(weapAtk, 'BurstCount')
-- How many individual player inputs can occur before depleting a magazine
local magTaps = statRead(weapAtk, 'ShotsPerMag')
-- How many additional projectiles are fired per ammo
local multishot = statRead(weapAtk, 'Multishot')
-- How much ammo is contained in the magazine
local magazine = statRead(weapAtk, 'Magazine')
-- How much ammo can be drawn from reserves (or?, how much ammo can be used without picking up more)
local ammoMax = statRead(weapAtk, 'AmmoMax')
-- Time^-1
local fireRate = statRead(weapAtk, 'FireRate')
-- Time
local shotTime = statRead(weapAtk, 'InterShotTime')
local chargeTime = statRead(weapAtk, 'ChargeTime')
local burstDelayTime = statRead(weapAtk, 'BurstDelay')
local reloadDelayTime = statRead(weapAtk, 'ReloadDelayEmpty')
local reloadTime = statRead(weapAtk, 'Reload')
local tapTime = chargeTime + (tapShots - 1) * burstDelayTime
-- tapTime: The time between the last shot fired and the next valid attack input
-- (omitting latency of course).
-- Note that first shot of any non-charge trigger attack is instantenous
local magDepletionTime = magTaps * tapTime
if magDepletionTime == 0 then -- If attack is not a charged attack
if shotTime == 0 then
shotTime = 1 / fireRate
end
magDepletionTime = magTaps / fireRate
end
local shotDelayTime = math.max(0, shotTime - tapTime)
-- Multiplier
local maxProgenitorBonus = statRead(weapAtk, 'IsLichWeapon') and 1.6 or 1
local avgCritMult = 1 + (statRead(weapAtk, 'CritMultiplier') - 1) * statRead(weapAtk, 'CritChance')
-- Damage
local biasPortion, biasType, hitDamage = statRead(weapAtk, 'DamageBias')
local avgDmgOnTap = hitDamage * avgCritMult * multishot * tapShots * maxProgenitorBonus
local avgDmgPerMag = avgDmgOnTap * magTaps
-- 1 is needed b/c one whole magazine is not included in reserve ammo count
-- If there is no reserve ammo, that means that weapon can deal an infinite amount of damage theoretically
local avgLifetimeDmg = (ammoMax ~= nil) and avgDmgPerMag * (1 + (ammoMax / magazine)) or math.huge
-- Damage / Time
local baseDps = hitDamage * multishot / shotTime
local avgSustainedDps = avgDmgPerMag / (magDepletionTime + reloadDelayTime + reloadTime) / tapShots
local avgBurstDps = avgDmgOnTap / (tapTime + shotDelayTime) / tapShots
-- Note that burst DPS can also be calculated as such:
-- local avgBurstDps = (hitDamage * avgCritMults * maxProgenitorBonus) * multishot / shotTime
-- local avgBurstDps = avgDmgPerMag / magDepletionTime
return StatObject.ucacheIn(weapAtk, 'CalcDamage',
{ hitDamage, avgDmgOnTap, avgBurstDps, avgSustainedDps, avgLifetimeDmg, baseDps, avgDmgPerMag }
)
end,
ShotDmg = indexes('CalcDamage', 1), -- Total damage per projectile
AvgShotDmg = indexes('CalcDamage', 2), AvgTapDmg = indexes('CalcDamage', 2), -- Average total damage per each input button
BurstDps = indexes('CalcDamage', 3), -- Average burst damage per second/DPS w/o reloading
SustainedDps = indexes('CalcDamage', 4), -- Average sustained damage per second/DPS w/ reloading
LifetimeDmg = indexes('CalcDamage', 5), -- Average total damage from entire ammo pool
BaseDps = indexes('CalcDamage', 6), -- Base damage per second w/ multishot w/o crit
MagDmg = indexes('CalcDamage', 7), -- Average total damage per magazine
-- Average damage scaled by melee attack speed multiplier (numerator of melee DPS w/o accounting for stances and animation time)
AvgDmgWithAnimSpeedMulti = function(weapAtk)
if statRead(weapAtk, 'IsMelee') then
-- Some melee weapons have attacks with multishot like Redeemer, Vastilok, and Quassus
return statRead(weapAtk, 'BaseDamage') * statRead(weapAtk, 'Multishot') * statRead(weapAtk, 'AttackSpeed')
end
return 0
end,
AttackSpeed = { --[[ors('AttackSpeed', 'FireRate')]]function(weapAtk)
if not statRead(weapAtk, 'IsMelee') then
error('AttackSpeed: Cannot get AttackSpeed attribute for a non-melee weapon; use p.statRead(weapAtk, "FireRate") instead')
end
return statRead(weapAtk, 'FireRate')
end, '%.2fx vitesse d\'animation'
},
IsMelee = function(weapAtk) return statRead(weapAtk, 'Slot'):find('Mêlée') ~= nil end,
IsSilent = ors('IsSilent', 'IsMelee', false),
HasAoEAttack = function(weap)
for i, attackEntry in pairs(weap['Attacks']) do
if attackEntry['ShotType'] == 'AoE' then
return true
end
end
return false
end,
Conclave = false,
Image = { 'Panel.png', '[[File:%s|link=]]' },
Attacks = ors('Attacks', p._getAttack, {}),
Family = nil,
FamilyList = { function(weapAtk)
local family = statRead(weapAtk, 'Family')
-- assert(family, 'i have no Family :\'(')
if not family then return {weapAtk} end
-- return family, statRead(weapAtk, 'Slot')
local slot = statRead(weapAtk, 'Slot')
local result = {}
for _, w in pairs(WeaponData[slot] or error('FamilyList: no weapondata for slot '..(slot or '<nil>'))) do
if w.Family == family then
table.insert(result, w)
end
end
table.sort(result, function(a,b) return a.Name<b.Name end)
return result
end, function(self, result)
for i,w in ipairs(result) do
result[i]=Tooltip.full(w.Name, 'Weapons', w)
end
return table.concat(result, '<br />')
end
},
BaseName = function(weapAtk) return weapAtk['BaseName'] or ({p._getVariant(statRead(weapAtk, 'Name'))})[3] end,
-- TODO: Add comments to Explosion function for readability
-- TODO: Do not rely on attack name to determine what AoE component is attached to which main direct hit component
---^i suggest an explosion key with either the attack number of any corresponding explosion, nested attack tables, or some other way to make a tree
-- TODO: Use ShotType = "AoE" to determine if attack entry is AoE
Explosion = function(weapAtk)
local weap, atk = weapAtk, weapAtk
-- tbh this is a mess
local explosion = weapAtk['Explosion'] or statRead(weapAtk, 'AttackName'):gsub(' Impact',''):gsub(' Contact','')..' Explosion'
if type(explosion) == 'string' then
explosion = weap.Attacks[tonumber(explosion:gsub('%D',''))] or explosion
elseif type(explosion) == 'number' then
explosion = weap.Attacks[explosion] or explosion
end
local explosions = {}
if type(explosion) ~= 'table' then
for i, v in ipairs(weap.Attacks) do
if p._statRead(weapAtk, v, 'AttackName'):find 'xplosion' then
if p._statRead(weapAtk, v, 'AttackName') == explosion then
explosions[1] = nil
explosion = v
break
end
table.insert(explosions, v)
end
end
explosion = explosions[1] or explosion
end
StatObject.pcacheIn(getWeaponAttack(weap, explosion), 'BaseAttack', atk)
return StatObject.pucacheIn(weapAtk, 'Explosion', explosion)
end,
IsVariant = function(weap)
return StatObject.pucacheIn(weap, 'IsVariant', p._isVariant(statRead(weap, 'Name')))
end,
Variant = indexes('IsVariant', 2),
BaseName = indexes('IsVariant', 3),
Categories = { function(weapAtk)
local cats = { 'Armes' }
-- Adding editor-defined traits from M:Weapons/data
-- Note to make sure they have a proper category page associated with a trait
for _, trait in ipairs(weapAtk.Traits or {}) do
local weapsTraitsMap = ({
-- De fabrication / origines
["Tenno"] = { "Tenno", "Armes/Tennos" },
["Corpus"] = { "Corpus", "Armes/Corpus" },
["Grineer"] = { "Grineer", "Armes/Grineers" },
["Infestée"] = { "Infestée", "Armes/Infestées" },
["Orokin"] = { "Orokin", "Armes/Orokins" },
["Sentient"] = { "Sentient", "Armes/Sentients" },
["Entrati"] = { "Entrati", "Armes/Entratis" },
["Céphalon"] = { "Céphalon", "Armes/Céphalons" },
-- Spéciales & Variantes
["Incarnon"] = { "Armes/Incarnon" },
["Principe"] = { "Armes/Principe" },
["Prisma"] = { "Armes/Prisma" },
["Vandal"] = { "Armes/Vandal" },
["Wraith"] = { "Armes/Wraith" },
["MK1"] = { "Armes/MK1" },
["Signature"] = { "Armes/Signature" },
["Liche Kuva"] = { "Liche Kuva", "Armes/Liche Kuva" },
-- Prime state
["Prime"] = { "Prime", "Armes/Prime" },
["Vaultée"] = { "Prime Vault", "Armes/Vault" },
["Jamais Vaultée"] = { "Jamais en Vault" },
-- Syndicats
["Syndicats"] = { "Armes de Syndicats" },
["Arbitres de Hexis"] = { "Arbitres de Hexis" }, -- Telos
["Céphalon Suda"] = { "Céphalon Suda" }, -- Synoid
["Méridien d'Acier"] = { "Méridien d'Acier" }, -- Vaykor
["Nouveau Loka"] = { "Nouveau Loka" }, -- Sancti
["La Séquence Perrin"] = { "La Séquence Perrin" }, -- Secura
["Voile Rouge"] = { "Voile Rouge" }, -- Rakta
["Céphalon Simaris"] = { "Céphalon Simaris" }, -- Special
-- Armes de "Factions" / PNJ
["Dax"] = { "Armes/Dax" },
["Duviri"] = { "Armes/Duviri" },
["Zariman"] = { "Armes/Zariman" },
["Cetus"] = { "Armes/Cetus" },
["Fortuna"] = { "Armes/Fortuna" },
["Puy de Cambion"] = { "Armes/Puy de Cambion" },
["Stalker"] = { "Stalker", "Armes/Stalker" },
["Baro"] = { "Offres de Baro Ki'Teer" },
-- Autres
["Dex"] = { "Armes/Dex" },
["Quête"] = { "Armes/Quêtes" },
["Fondateur"] = { "Fondateur", "Armes/Fondateur" },
["Invasions"] = { "Invasions", "Récompenses d'évènements", "Armes/Invasions", "Armes/Évènements" },
["Alertes Tactiques"] = { "Récompenses d'Alertes Tactiques" },
})[trait]
if weapsTraitsMap then
for _, cat in ipairs(weapsTraitsMap) do
table.insert(cats, cat)
end
else
table.insert(cats, "Armes/Incomplètes")
end
end
-- DamageTypes categories
local bias = p._getValue(weapAtk, "BiasType")
table.insert(cats, ({
-- Physic
["Impact"] = "Armes/Dégâts/Impact",
["Tranchant"] = "Armes/Dégâts/Tranchant",
["Perforation"] = "Armes/Dégâts/Perforation",
-- Elemental
-- -- Main
["Feu"] = "Armes/Dégâts/Feu",
["Glace"] = "Armes/Dégâts/Glace",
["Poison"] = "Armes/Dégâts/Poison",
["Électrique"] = "Armes/Dégâts/Électrique",
-- -- Mixed
["Gaz"] = "Armes/Dégâts/Gaz",
["Viral"] = "Armes/Dégâts/Viral",
["Corrosif"] = "Armes/Dégâts/Corrosif",
["Explosif"] = "Armes/Dégâts/Explosif",
["Radiation"] = "Armes/Dégâts/Radiation",
["Magnétique"] = "Armes/Dégâts/Magnétique",
-- -- Specials
["Tau"] = "Armes/Dégâts/Tau",
["Brut"] = "Armes/Dégâts/Brut",
["Néant"] = "Armes/Dégâts/Néant",
})[bias] or "Armes/Dégâts/Inconnus")
local class = p._getValue(weapAtk, "Class")
table.insert(cats, ({
-- Principales
["Canon à bras"] = "Armes/Canons à bras",
["Arc"] = "Armes/Arcs",
["Arbalète"] = "Armes/Arcs",
["Fusil"] = "Armes/Fusils",
["Fusil Sniper"] = "Armes/Fusils de Sniper",
["Fusil à Pompe"] = "Armes/Fusils à Pompe",
["Lance à énergie"] = "Armes/Lances à énergie",
["Lanceur"] = "Armes/Lanceurs",
-- Secondaires
["Doubles Pistolets"] = "Armes/Doubles Pistolets",
["Fusil à Pompe à double canon"] = "Armes/Fusils à Pompe à double canon",
["Fusil à Pompe court"] = "Armes/Fusils à Pompe courts",
["Lancé"] = "Armes/Lancés",
["Pistolet"] = "Armes/Pistolets",
["Volume"] = "Armes/Volumes",
-- Mêlées
["Arme d'hast"] = "Armes/Armes d'hast",
["Bâton"] = "Armes/Bâtons",
["Dague"] = "Armes/Dagues",
["Doubles Dagues"] = "Armes/Doubles Dagues",
["Doubles Nikanas"] = "Armes/Doubles Nikanas",
["Doubles Épées"] = "Armes/Doubles Épées",
["Faux"] = "Armes/Faux",
["Faux Lourde"] = "Armes/Faux Lourdes",
["Fouet"] = "Armes/Fouets",
["Glaive"] = "Armes/Glaives",
["Griffes"] = "Armes/Griffes",
["Lame Lourde"] = "Armes/Lames Lourdes",
["Lame et Fouet"] = "Armes/Lames et Fouets",
["Machette"] = "Armes/Machettes",
["Mains et Pieds"] = "Armes/Mains et Pieds",
["Marteau"] = "Armes/Marteaux",
["Nikana"] = "Armes/Nikanas",
["Nikana à Deux Mains"] = "Armes/Nikanas à Deux Mains",
["Nunchaku"] = "Armes/Nunchakus",
["Pistolame"] = "Armes/Pistolames",
["Poings"] = "Armes/Poings",
["Rapière"] = "Armes/Rapières",
["Scie d'Assaut"] = "Armes/Scies d'Assaut",
["Tonfa"] = "Armes/Tonfas",
["Épée"] = "Armes/Épées",
["Épée et Bouclier"] = "Armes/Épées et Boucliers",
["Éventail de guerre"] = "Armes/Éventails de guerre",
-- Spéciales
["Arme Exaltée"] = "Armes/Exaltées",
["Amplificateur"] = "Armes/Amplificateurs",
["Arch-Fusil"] = "Armes/Arch-Fusils",
["Arch-Fusil (Atmosphère)"] = "Armes/Arch-Fusils",
["Arch-Mêlée"] = "Armes/Arch-Mêlées",
["Pièce principale"] = "Armes/Railjack",
["Tourelle"] = "Armes/Railjack",
["Railjack Armament"] = "Armes/Railjack",
["Unique"] = "Armes/Uniques", -- e.g Parazon/Robotiques/Molosses
-- Zaws
["Zaw Rapière / Arme d'hast"] = "Armes/Zaws",
["Zaw Machette / Marteau"] = "Armes/Zaws",
["Zaw Faux / Bâton"] = "Armes/Zaws",
["Zaw Nikana / Bâton"] = "Armes/Zaws",
["Zaw Épée / Bâton"] = "Armes/Zaws",
["Zaw Épée / Arme d'hast"] = "Armes/Zaws",
["Zaw Machette / Arme d'hast"] = "Armes/Zaws",
["Zaw Faux / Lame Lourde"] = "Armes/Zaws",
["Zaw Machette / Arme d'hast"] = "Armes/Zaws",
["Zaw Dague / Bâton"] = "Armes/Zaws",
["Zaw Rapière / Arme d'hast"] = "Armes/Zaws",
-- Kitguns
["Fusil Kitgun"] = "Armes/Kitguns",
["Lanceur Kitgun"] = "Armes/Kitguns",
["Pistolet Kitgun"] = "Armes/Kitguns",
["Fusil à Pompe Kitgun"] = "Armes/Kitguns",
})[class] or "Armes/Inconnues")
-- Modular category ('Armes/Modulaires')
if string.find(class, "^Zaw") or string.find(class, "Kitgun$") then
table.insert(cats, "Armes/Modulaires")
end
local family = p._getValue(weapAtk, "Family")
table.insert(cats, family)
local slot = p._getValue(weapAtk, "Slot")
table.insert(cats, ({
["Principale"] = "Armes/Principales", -- Principale
["Secondaire"] = "Armes/Secondaires", -- Secondaire
["Mêlée"] = "Armes/Mêlées", -- Mêlée
-- Archwing
["Arch-Fusil"] = "Armes/Arch-Fusils",
["Arch-Fusil (Atmosphère)"] = "Armes/Arch-Fusils",
["Arch-Mêlée"] = "Armes/Arch-Mêlées",
-- Railjack
["Tourelle Railjack"] = "Armes/Railjacks",
["Pièce principale Railjack"] = "Armes/Railjacks",
--
["Amplificateur"] = "Armes/Amplificateurs", -- Amplificateurs
["Robotique"] = "Armes/Robotiques", -- Sentinelles
["Molosse"] = "Armes/Molosses", -- Molosses
["Emplacement"] = "Armes/Emplacements", -- Rempart (only)
["Équipement"] = "Armes/Équipements", -- Ebisu / Lanzo / etc..
["Nech-Mêlée"] = "Armes/Nech-Mêlées", -- Pugil
["Unique"] = "Armes/Uniques", -- e.g Parazon
["Véhicule"] = "Armes/Véhicules", -- Dargyn
})[slot] or "Armes/Inconnues")
-- Fonctionnalité désactivée pour y insérer un tableau associatif juste après ce commentaire (Yazuh)
-- local trigger = p._getValue(weapAtk, "Trigger")
-- table.insert(cats, 'Armes ' .. trigger)
table.insert(cats, ({
["Activée"] = 'Armes/Tir à Activation',
["Auto / Chargée"] = 'Armes/Chargée',
["Automatique"] = 'Armes/Automatique',
["Auto / Rafale"] = 'Armes/Tir en Rafale',
["Cadence progressive"] = 'Armes/Automatique',
["Rafale"] = 'Armes/Tir en Rafale',
["Chargée"] = 'Armes/Chargée',
["Duplex"] = 'Armes/Tir en Duplex',
["Maintenue"] = 'Armes/Tir en continu',
["Semi-auto"] = 'Armes/Semi-automatique',
})[trigger] or 'Armes') -- fix for melee weapon (no trigger)
local users = p._getValue(weapAtk, "Users") or {}
for _, user in ipairs(users) do table.insert(cats, user) end
-- Aucun besoin de cette fonctionnalité (by: Yazu)
-- local variant = p._getValue(weapAtk, "Variant")
-- table.insert(cats, variant)
local infAmmo = p._getValue(weapAtk, "AmmoMax") == math.huge
local accuracy = p._getValue(weapAtk, "Accuracy")
local pinpoint = accuracy ~= nil and accuracy >= 100
local regens = p._getValue(weapAtk, "ReloadRate") > 0
local silent = weapAtk.IsSilent -- automatically includes
local single = p._getValue(weapAtk, "Magazine") == 1 and not p._getValue(weapAtk, "IsMelee")--meh, delet?
local spools = p._getValue(weapAtk, "Spool") > 0
local isAoE = p._getValue(weapAtk, "HasAoEAttack")
local isCodexSecret = p._getValue(weapAtk, "CodexSecret")
local isTradable = p._getValue(weapAtk, "Tradable")
local isInConclave = p._getValue(weapAtk, "Conclave")
-- Arbitrarily ordering misc categories
if infAmmo then table.insert(cats, 'Armes/Armes à munitions infinies') end
if pinpoint then table.insert(cats, 'Armes/Armes de précision') end
if regens then table.insert(cats, 'Armes/Armes à batterie') end
if silent then
table.insert(cats, 'Armes/Armes silencieuses')
else
table.insert(cats, 'Armes/Armes bruyantes')
end
if single then table.insert(cats, 'Armes/Armes à coup unique') end
if spools then table.insert(cats, 'Armes/Armes à bobine') end
if isAoE then table.insert(cats, 'Armes/Armes à zone d\'effet') end
if isCodexSecret then table.insert(cats, 'Armes/Secret du codex') end
if isTradable then
table.insert(cats, 'Armes/Armes échangeables')
else
table.insert(cats, 'Armes/Armes non échangeables')
end
if isInConclave then table.insert(cats, 'Armes/Disponibles au Conclave') end
return StatObject.cacheIn(weapAtk, 'Categories', cats)
end, function(s, cats)
local wikitextResult = { '' } -- Need to prepend a newline so first asterisk is rendered as a wikitext list
local formatStr = '*[[:Catégorie:%s|%s]][[Catégorie:%s]]'
for _, category in ipairs(cats) do
table.insert(wikitextResult, formatStr:format(category, category, category))
end
return table.concat(wikitextResult, '\n')
end
},
SyndicateEffect = { '', function(s, v)
return (v == '' or type(v) ~= 'string') and '' or Tooltip.icon(({
['rouille'] = 'Voile Rouge',
['entropie'] = 'Céphalon Suda',
['justice'] = 'Méridien d\'Acier',
['pureté'] = 'Nouveau Loka',
['séquence'] = 'La Séquence Perrin',
['vérité'] = 'Arbitres de Hexis',
})[v:lower()] or 'Tenno', 'Factions')
..' '..v
end
},
MinProgenitorBonus = function(weap) return weap.IsLichWeapon and statRead(weap, 'BaseDamage') * 0.25 or 0 end,
ProgenitorBonus = function(weap) return weap.IsLichWeapon and statRead(weap, 'BaseDamage') * 0.6 or 0 end,
Class = '',
SniperComboReset = { nil, '%.1f s' },
SniperComboMin = { nil, '%d shot(s)' },
Tradable = { function(weapAtk)
if type(weapAtk['Tradable'])=='number' then
assert(weapAtk['Tradable']<=5,
'Tradable: Does not support tradeability enums beyond 5; please update [[Module:Weapons/data]] and [[Module:Weapons]] to support more tradeability edge cases')
return ({
[0]=false,
[1]='Rang 0',
[2]='Parties',
[3]='Liches',
[4]='Parties pour fabrication',
[5]='Arme liée',
})[weapAtk['Tradable']]
end
return weapAtk['Tradable']
end, function(s, tradable)
return ({
[false] = 'Non-échangeable',
['Unranked'] = 'Non classée sans Forma ou Catalyseur',
['Parts'] = 'Pièces et/ou schéma uniquement',
['Lich'] = 'Par le biais des échanges des [[Liche Kuva|Liches]].',
['Built Parts'] = 'Uniquement des composants construits, et non des schémas',
['Parent'] = 'Indirectement, livré avec le compagnon associé',
})[tradable] or 'Non-échangeable?'
end
},
SellPrice = { nil, function(self, sellPrice)
if sellPrice == nil then
return 'Invendable'
end
return Tooltip.icon('Crédits', 'Resources')..' '..Math.formatnum(sellPrice)
end
},
DefaultUpgrades = { nil, function(self, upgradesArr)
local result = {}
for _, modIndex in ipairs(upgradesArr or {}) do
table.insert(result, Tooltip.full(modIndex, 'Mods'))
end
return table.concat(result, '<br />')
end
},
Users = { nil, function(self, usersArr)
local result = { '' }
for _, user in ipairs(usersArr or {}) do
table.insert(result, '*[['..user..']]')
end
return table.concat(result, '\n')
end
},
Zoom = { unpacks('Zoom'), { sep = '<br />' } },
Slot = nil,
}
-- Loops for adding to StatObject.default table
-- Damage type getters:
-- <DamageType> = damage type value
-- <DamageType>Distribution = damage type distribution as a percentage
-- PvP<DamageType> = damage type value with precise formatting for PvP purposes
for _, damageType in ipairs(iterationOrderArray) do
StatObject.default[damageType] = {
function(weapAtk) return weapAtk['Damage'][damageType] or 0 end,
function(self, value) return Tooltip.icon(damageType, 'DamageTypes')..' '..Math.formatnum(value) end
}
-- Damage distribution as a percentage
StatObject.default[damageType..'Distribution'] = {
function(weapAtk) return weapAtk['Damage'][damageType] / statRead(weapAtk, 'BaseDamage') end,
function(self, value) return Tooltip.icon(damageType, 'DamageTypes')..' '..Math.percentage(value) end
}
-- More precise damage values to 4 decimal places for PvP
StatObject.default['PvP'..damageType] = {
function(weapAtk) return weapAtk['Damage'][damageType] or 0 end,
Tooltip.icon(damageType, 'DamageTypes')..' %.4f'
}
end
-- TODO: Do not rely on localized name to determine a weapon's variant. Decouple localization from data
--- Checks if a weapon is a variant or not.
-- @function p._isVariant
-- @param {string} weaponName Weapon name
-- @returns {boolean} True if weapon is a variant, false otherwise
-- @returns {string} Weapon's variant name or "Base" if weapon is not a variant
-- @returns {string} Weapon name, same as weaponName
function p._isVariant(weaponName)
for i, var in pairs(VARIANT_LIST) do
if (var ~= "Dex" or weaponName ~= "Dex Pixia") then
if string.find(weaponName, var) then
return true, var, (string.gsub(weaponName, " ?"..var.." ?-?", ""))
end
end
end
return false, "Variante de base", weaponName
end
--- Builds the full name of a weapon's variant. Does not check if it exists or not.
-- @function p._buildName
-- @param {string} baseName Weapon's base name (e.g. "Braton")
-- @param[opt] {string} variant Variant name (e.g. "Vandal"); if nil, returns base weapon name instead
-- @returns {string} Weapon's variant name (e.g. "Braton Vandal")
function p._buildName(baseName, variant)
if not variant or variant == 'Base' or variant == '' then
return baseName
end
return (({
-- Prime Laser Rifle is an edge case for Prime naming scheme (at least in EN localization)
Prime = baseName ~= 'Fusil Laser' and '%b %v',
Vandal = '%b %v',
Wraith = '%b %v',
MK1 = '%v-%b',
})[variant] or '%v %b'):gsub('%%v', variant):gsub('%%b', baseName)
end
--- Returns a specific weapon table entry from <code>/data</code> or <code>/Conclave/data</code>.
-- @function p._getWeapon
-- @param {string} weaponName Weapon name
-- @param[opt] {boolean} pvp If true, gets PvP stats of weapon instead, false otherwise; defaults to false
-- @returns {table} Weapon table
function p._getWeapon(weaponName, pvp)
weaponName = mw.text.decode(weaponName)
return (pvp and ConclaveData or WeaponData)[weaponName] or
error('p._getWeapon(weaponName, pvp): "'..weaponName..
'" does not exist in '..(pvp and '[[Module:Weapons/Conclave/data]]' or '[[Module:Weapons/data]]'))
end
--- Gets the raw value of a certain statistic of a weapon.
-- @function p._getValue
-- @param {table} Weapon Weapon table
-- @param {string} key Name of key
-- @param[opt] {string} attack Name of attack to search through; defaults to 'Attack1' or what '_TooltipAttackDisplay' is set to
-- @returns {string, number} Value of statistic
function p._getValue(weap, key, atk)--, formatted)
-- return (formatted and statFormat or statRead)(weap, atk, key)
return p._statRead(weap, atk, key)
end
--- Gets the formatted value of a certain statistic of a weapon to be displayed
-- the wiki.
-- @function p._getFormattedValue
-- @param {table} Weapon Weapon table
-- @param {string} keyName Name of key
-- @param[opt] {string} attackName Name of attack to search through; defaults to 'Attack1'
-- @returns {string} Value of statistic
function p._getFormattedValue(weap, key, atk)
-- return p._getValue(Weapon, keyName, attackName, true)
return p._statFormat(weap, atk, key)
end
--- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair.
-- @function p._statReader
-- @param {table} weap Weapon entry
-- @param {number|table} atk Attacks table index or Attack entry
-- @return {function} Getter function
function p._statReader(weap, atk)
return function(...) return p._statRead(weap, atk, ...) end
end
--- Function that returns a simpler getter function, for multiple _stat*() calls on the same weapon/attack pair.
-- @function p._statFormatter
-- @param {table} weap Weapon entry
-- @param {number|table} atk Attacks table index or Attack entry
-- @return {function} Getter function
function p._statFormatter(weap, atk)
return function(...) return p._statFormat(weap, atk, ...) end
end
--- Returns a subset of <code>/data</code> or <code>/Conclave/data</code> based on a validation function.
-- @function p._getWeapons
-- @param {function} validateFunction Function that filters out a weapon by taking in a Weapon table argument
-- @param[opt] {string} source Name of weapon entry to use
-- @param[opt] {boolean} ignoreIgnore If true, ignores the _IgnoreEntry flag, false otherwise; defaults to false
-- @param[opt] {function} sortFunc Custom comparison function; false -> no sorting; defaults to sorting in ascending order by weapon name
-- @returns {table} Table of weapon table entries as seen in <code>/data</code>
function p._getWeapons(validateFunction, source, opts)
opts=opts or {}
local ignoreIgnore, sortFunc, pvp = opts.ignoreIgnore, opts.sortFunc, opts.pvp
validateFunction = validateFunction or function() return true end
local data = pvp and ConclaveData or WeaponData
if source then
data = data[source]
end
local weaps = {}
for _, weap in pairs(data) do
if (ignoreIgnore or not weap['_IgnoreEntry']) and validateFunction(weap) then
table.insert(weaps, weap)
end
end
if sortFunc ~= false then
table.sort(weaps, sortFunc or function(a, b) return a.Name < b.Name end)
end
return weaps
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.
-- @function p._getMeleeWeapons
-- @param[opt] {boolean} weapType
-- @param[opt] {boolean} pvp If true, only gets melee weapons available in Conclave, false otherwise; defaults to false
-- @returns {table} An array of melee weapon table entries as seen in <code>/data</code>
function p._getMeleeWeapons(weapType,pvp)
return p._getWeapons(weapType and function(weap) return weap.Class==weapType end, 'mêlée',{['pvp']=pvp==true})
end
--- Main frame invokable function to access any raw/computed attribute/column/key of a weapon entry.
-- See default table in M:Weapons to see all valid computed attributes.
-- @function p.getValue
-- @param {string} weap Weapon name in EN locale
-- @param {number} atk Attacks table index
-- @param {string} k Key name
-- @return Raw or computed value associated with k key
function p.getValue(frame)
-- table.unpack doesn't work on the frame object which is why this is anonymous function is needed
local weap, key, atk = (function(t) return t[1], t[2], t[3] end)(frame.args)
weap = p._getWeapon(weap)
return p._getValue(weap, key, atk)
end
--- Main frame invokable function to access any formatted attribute/column/key of a weapon entry.
-- See default table in M:Weapons to see all valid computed attributes.
-- @function p.getFormattedValue
-- @param {string} weap Weapon name in EN locale
-- @param {number} atk Attacks table index
-- @param {string} k Key name
-- @return Formatted value associated with k key
function p.getFormattedValue(frame)
local weap, key, atk = (function(t) return t[1], t[2], t[3] end)(frame.args)
weap = p._getWeapon(weap)
return p._getFormattedValue(weap, key, atk)
end
--- Builds a melee weapon gallery as seen on [[Template:MeleeCategory]].
-- @function p.getMeleeWeaponGallery
-- @param {table} frame Frame object w/ first argumenting being string meleeClass
-- @returns {string} Resultant wikitext of gallery
function p.getMeleeWeaponGallery(frame)
local meleeClass = frame.args[1] or ''
local result = { "== Armes de type : "..meleeClass.."==", '<gallery widths="200" position="center" spacing="small">' }
for i, weap in ipairs(p._getMeleeWeapons(meleeClass)) do
table.insert(result, p._statRead(weap, nil, 'Image')..'|'..p._statFormat(weap, nil, 'Name'))
end
table.insert(result, '</gallery>')
return frame:preprocess(table.concat(result, '\n')) -- annoying that it needs to be preprocessed
end
--- Gets the total count of weapons as used on [[Mastery Rank#Total Mastery]].
-- @function p.getWeaponCount
-- @param {table} frame Frame object w/ the first argument being the weaponSlot and the
-- second argument being a boolean to getFullList
-- @returns {number} Total count of weapons in a certain category/type
-- @returns {table} List of weapon names that count for mastery in a particular weapon slot
function p._getWeaponCount(slot)
slot = slot and slot:lower()
local data = slot and WeaponData[slot] or WeaponData
local fullList = {}
for name, weapon in pairs(data) do
if not weapon._IgnoreInMasteryCount then
-- TODO: There should be a better way to determine/differentiate if a weapon is a kitgun b/c kitguns and zaws
-- are stored in the same M:Weapons/data/modular data store; add a new "Kitgun" or "Zaw" Trait and target that?
if (slot == 'kitgun' and weapon.Slot == 'Secondaire')
or (slot == 'zaw' and weapon.Slot == 'Mêlée')
or (slot == 'robotic' and weapon.Slot ~= 'Molosse')
or (weapon.Slot:lower() == slot)
or slot == nil then
fullList[#fullList + 1] = name
end
end
end
return #fullList, fullList
end
--- Gets the total count of weapons as used on [[Mastery Rank#Total Mastery]].
-- @function p.getWeaponCount
-- @param {table} frame Frame object w/ the first argument being the weapon slot
-- @return {number} Total number of weapons that can reward Mastery XP
function p.getWeaponCount(frame)
return (p._getWeaponCount(frame.args and frame.args[1] or nil))
end
--- Builds wikitable of all weapons' innate polarities as seen on [[Polarity]].
-- @function p.getPolarityTable
-- @param {table} frame Frame object
-- @returns {string} Wikitext of resultant wikitable
function p.getPolarityTable(frame)
local colNames = { 'Principale', 'Secondaire', 'Mêlée', 'Arch-Fusil', 'Arch-Mêlée' }
local cols = {} -- Will look like: {['Primary']={},['Secondary']={},['Melee']={},['Arch-Gun']={},['Arch-Melee']={},}
local colOrder = {} --{cols['Primary'],cols['Secondary'],cols['Melee'],cols['Arch-Gun'],cols['Arch-Melee'],}
local colCounts = {}
for i, v in ipairs(colNames) do
cols[v] = {}
colOrder[i] = cols[v]
colCounts[v] = 0
end
for _, weapon in pairs(WeaponData) do
local pols = Table.size(weapon["Polarities"] or {})
local slot = weapon['Slot']
if pols > 0 and cols[slot] then
table.insert(cols[slot], {
'|'..p._getFormattedValue(weapon, 'NameLink'):gsub(' ?%(.*%)', '')..'||'..p._getFormattedValue(weapon, "Polarities"),
pols
})
colCounts[slot] = colCounts[slot] + 1
end
end
for i, v in ipairs(colNames) do
colCounts[i] = colCounts[v]
table.sort(cols[v], function(a, b)return a[2] > b[2] end)
end
local result = {[=[
{| style="width: 100%; border-collapse: collapse;" cellpadding="2" border="1"
|+ '''Armes avec une Polarité innée (en ignorant la Posture et l'emplacement Exilus)'''
! colspan="2" |Principales
! colspan="2" |Secondaires
! colspan="2" |Mêlées
! colspan="2" |Arch-Fuils
! colspan="2" |Arch-Mêlées]=]}
for i = 1, math.max(table.unpack(colCounts)) do --row
table.insert(result, '|-')
for _, col in ipairs(colOrder) do --cell
table.insert(result,(col[i] or {'| ||'})[1])
end
end
table.insert(result, '|}')
return table.concat(result, '\n')
end
--- Builds a table that lists out all weapons with a certain damage type
-- @function p.buildDamageTypeTable
-- @param {table} frame Frame object
-- @returns {string} Wikitext of resultant wikitable
function p.buildDamageTypeTable(frame)
local damageType = frame.args and frame.args[1] or frame
local mostly = frame.args and (frame.args[2] or '') ~= ''
local content = {}
for k,weap in pairs(WeaponData) do
local weapAtk = getWeaponAttack(weap)--could add a loop here
local portion, biastype, damage = statRead(weapAtk, 'DamageBias')
local typeDmg = statRead(weapAtk, damageType)
if damage == 0 then typeDmg = weapAtk[damageType] and 1 or 0 end--modular pieces
--Filter for
--a. any of the damage type in any attack - former 'not mostly'
--b. at least one majority damage type - former 'mostly'
--c. a majority of the damage type in the display attack - 'mostly'
--d. any of the damage type in the display attack - 'not mostly'
if biastype == damageType or not mostly and typeDmg > 0 then
table.insert(content, ('| %s || %s || %s || %s || %s || data-sort-value="%s" | %s'):format(
statFormat(weapAtk, 'Name'),
statRead(weapAtk, 'Slot'),
statRead(weapAtk, 'Class'),
statRead(weapAtk, 'AttackName'),
typeDmg,
portion, statFormat(weapAtk, 'DamageBias')
))
end
end
table.sort(content)--will sort by tooltip span key
return ([[
{| class = "listtable sortable" style="margin:auto;"
|+ '''Armes avec des dégâts %s%s'''
|-
! Nom !! Emplacement !! Classe !! Nom de l'attaque !! data-sort-type="number" | %s !! data-sort-type="number" | Majorité
|-
]]):format(mostly and 'mostly ' or '', damageType, Tooltip.full(damageType, 'DamageTypes'))
..table.concat(content, '\n|-\n')..'\n|}'
end
--- _isVariant adapter for p._shortLinkList
local function variantOf(weap)
local full, _, var, base = weap.Name, p._isVariant(weap.Name)
return var, base, full
end
--- Builds a list of weapons, with variants being next to base weapon name inside parentheses
-- (e.g. {{Weapon|Braton}} ({{Weapon|MK1-Braton|MK1}}, {{Weapon|Braton Prime|Prime}})).
-- @function p._shortLinkList
-- @param {table} Weapon Weapon table
-- @param {boolean} tooltip If true, adds weapon tooltips, false otherwise; defaults to false
-- @returns {string} Wikitext of resultant list
function p._shortLinkList(Weapons, tooltip)
return StatObject.shortLinkList(Weapons, variantOf, tooltip and 'Weapons')
end
--- Builds a list of weapons' mastery requirements as seen on [[Template:EquipmentUnlock]],
-- [[Template:EquipmentUnlock/Primary]], [[Template:EquipmentUnlock/Secondary]],
-- [[Template:EquipmentUnlock/Melee]], etc.
-- @function p.getMasteryShortList
-- @param {table} frame Frame object w/ first argument being a string weaponSlot
-- @returns {string} Wikitext of resultant list
function p.getMasteryShortList(frame)
local weaponSlot = frame.args[1]
local masteryRank = tonumber(frame.args[2])
local weapArray = p._getWeapons(function(x)
return x.Slot == weaponSlot and x.Mastery == masteryRank
end)
return table.concat(StatObject.shortLinkList(weapArray, variantOf, 'Weapons'), ' • ')
end
function p.fullList()
return table.concat(StatObject.shortLinkList(WeaponData, variantOf, 'Weapons'), ' • ')
end
--- Builds a list of PvP weapons as seen on [[PvP#Limitations]].
-- @function p.getConclaveList
-- @param {table} frame Frame object w/ first argument being a string weaponSlot
-- @returns {string} Wikitext of resultant list
function p.getConclaveList(frame)
local weaponSlot = frame.args[1] or 'All'
local weapArray = p._getWeapons(function(weap)
return weap.Conclave == true
end, weaponSlot, {pvp=true})
return '*'..table.concat(StatObject.shortLinkList(weapArray, variantOf), '\n* ')
end
--- Builds a disposition wikitable as seen on [[Riven Mods/Weapon Dispos]].
-- @function p.getRivenDispositionTable
-- @param {table} frame Frame object w/ first argument being a string weaponSlot
-- @returns {string} Wikitext of resultant wikitable
function p.getRivenDispositionTable(frame)
local weaponSlot = frame.args[1]
local result = {
'{| class="article-table" border="0" cellpadding="1" cellspacing="1" style="width: 100%"',
'|-',
{'[[a| '}, -- Wikitable header row
'|-'
}
-- local ranges = {'○○○○○', '●○○○○', '●●○○○', '●●●○○', '●●●●○', '●●●●●'}
local dispo = {}
for k, weapon in pairs(WeaponData) do
if weapon['Disposition'] and (weaponSlot == 'All' or weapon['Slot'] == weaponSlot) then
local disp = p._statFormat(weapon, nil, 'Dispo')
dispo[disp] = dispo[disp] or {}
table.insert(dispo[disp], weapon)
end
end
for str, dis in Table.skpairs(dispo) do
table.sort(dis, function(a, b) return a['Disposition'] > b['Disposition'] end)
local col = { '| style="vertical-align:top; font-size:small" |' }
for _, weap in ipairs(dis) do
table.insert(col, p._statFormat(weap, nil, 'NameLink')..' ('..weap['Disposition']..')')
end
table.insert(result[3], str)
table.insert(result, table.concat(col, '\n* '))
end
result[3] = table.concat(result[3], ']]\n! scope="col" style="text-align:center;"|[[Mods Riven#Disposition|')..']]'
table.insert(result, '|}')
return table.concat(result, '\n')
end
--- Builds a simple div in the Weapon part of the abilities if an Exalted Weapon is existing.
-- @function p.buildAbilityWeaponTab
-- @return <table> with weapLink, main page link, weapImg, introSection, fetched from the main Weapon page
function p.buildAbilityWeaponTab(frame)
local abilityName = frame.args[1]
local AbilityWeaponTab = {}
for _, weap in pairs(WeaponData) do
if weap.WeaponAugment then
if abilityName == weap.WeaponAugment then
if weap.Name ~= "Lame Exaltée Prime" and weap.Name ~= "Lame Exaltée Umbra" then -- escape duplicate entries
table.insert(AbilityWeaponTab, ([==[
{| id="AbilityWeaponTab" style="width: %s; background-color: #2a2a31; text-align: center; padding: 1rem;"
|-
| rowspan=2 | [[Fichier:%s|200px]] || [[%s]]
|-
| %s
|}
]==]):format(
'100%', -- escape auto-format
weap.Image or 'Panel.png',
weap.Link or 'Lien non trouvé.[[Catégorie:AbilityWeaponTab error]]',
frame:expandTemplate{ title = 'fetchSection', args = {weap.Link, 'intro'} } or 'Aucune description trouvée sur la page.[[Catégorie:AbilityWeaponTab error]]'
))
end
end
end
end
-- close and return table
return table.concat(AbilityWeaponTab, "")
end
function p.getSignatureWeaponsTable(frame)
local signWpsTable = mw.html.create("table"):addClass("bigmodtable sortable"):css("width", "100%") -- main Table
-- build main Table headings
signWpsTable:tag("tr")
:tag("th"):wikitext('Warframe/Compagnon'):done()
:tag("th"):attr("data-sort-type", "text"):wikitext('Arme(s)'):done()
:tag("th"):addClass("unsortable"):wikitext('Synergie'):done()
:done()
for key, weaps in pairs(WeaponData) do
if weaps.Traits then
for x, traits in pairs(weaps.Traits) do
if traits == "Signature" then
if weaps.SignatureTags and weaps.SignatureDesc then
local WFAndCompanions = {}
-- Ajouter les éléments de weaps.SignatureTags.Warframes
if weaps.SignatureTags.Warframes then
for _, wfs in pairs(weaps.SignatureTags.Warframes) do
table.insert(WFAndCompanions, Tooltip.full(wfs, "Warframes"))
end
end
-- Ajouter les éléments de weaps.SignatureTags.Companions
if weaps.SignatureTags.Companions then
for _, comps in pairs(weaps.SignatureTags.Companions) do
table.insert(WFAndCompanions, Tooltip.full(comps, "Companions"))
end
end
-- Afficher les informations
signWpsTable:tag("tr")
:tag("td"):wikitext(table.concat(WFAndCompanions, '<br/>')):done()
:tag("td"):wikitext(Tooltip.full(weaps.Name, "Weapons")):done()
:tag("td"):wikitext(weaps.SignatureDesc):done()
:done()
end
end
end
end
end
signWpsTable:allDone()
return frame:preprocess(tostring(signWpsTable))
end
return p