| 🌟 | 現在、 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
モジュール:WeaponInfobox
ナビゲーションに移動
検索に移動
このモジュールについての説明文ページを モジュール:WeaponInfobox/doc に作成できます
require('Module:Utility/mw.html Extensions')
local p = {}
local cfg = mw.loadData('Module:WeaponInfobox/configuration')
local aw = require('Module:Utility/Library')
local iu = require('Module:Utility/Image')
local nu = require('Module:Utility/Name')
local proto = require('Module:Utility/Prototypes')
local formatter -- lazily initialized
local getArgs -- lazily initialized
local function calcBurstAverageRPS(stat, delay)
delay = delay or stat.firerate.burst_delay
return stat.mode.burst / ((stat.mode.burst - 1) / stat.firerate.burst + delay)
end
local function calcRechamberRPS(firerate, rechamber)
rechamber = rechamber or firerate.single_rechamber
return 1 / (1 / firerate.single + rechamber)
end
local function createCellInRow(tbl, name)
return tbl:tag('tr')
:tag('th')
:wikitext(name)
:done()
:tag('td')
end
local function renderRow(tbl, name, item)
createCellInRow(tbl, name):wikitext(item)
end
local function renderFormatRow(tbl, name, default, common, rare, epic, opts)
opts = opts or {}
opts.separator = opts.separator or ' - '
local row = tbl:tag('tr')
:addClassIf(opts.class and type(opts.class) == 'string', opts.class)
if name ~= nil then
row:tag('th')
:attrIf(opts.headerAlign and type(opts.headerAlign) == 'string', { align = opts.headerAlign })
:wikitext(name)
end
local first = true
if default ~= nil then
first = false
row:tag('td')
:addClass('cell-type-number')
:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
:wikitext(default)
end
if common ~= nil then
if not first then
row:tag('td'):wikitext(opts.separator)
end
first = false
row:tag('td')
:addClass('cell-type-number')
:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
:wikitext(formatter:common(common))
end
if rare ~= nil then
if not first then
row:tag('td'):wikitext(opts.separator)
end
first = false
row:tag('td')
:addClass('cell-type-number')
:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
:wikitext(formatter:rare(rare))
end
if epic ~= nil then
if not first then
row:tag('td'):wikitext(opts.separator)
end
first = false
row:tag('td')
:addClass('cell-type-number')
:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
:wikitext(formatter:epic(epic))
end
if opts.footer ~= nil then
row:tag('td')
:attrIf(opts.footerAlign and type(opts.footerAlign) == 'string', { align = opts.footerAlign }, { align = 'left' })
:attrIf(opts.footerColspan and type(opts.footerColspan) == 'number', { colspan = opts.footerColspan })
:wikitext(opts.footer)
end
return row
end
local function renderReleaseDate(tbl, cfg, release)
local r = os.date("*t", release)
local releaseText = string.format(
'<time datetime="%04d-%02d-%02dT%02d:00:00.000+0900">%d年%d月%d日 %d時</time>~',
r.year, r.month, r.day, r.hour, r.year, r.month, r.day, r.hour)
renderRow(tbl, cfg.name, releaseText)
end
local function renderCategory(tbl, cfg, stat, lang)
local category = nu.type(stat, lang, 1)
local item
if lang == 'ja' then
item = string.format('[[武器#%s|%s]][[Category:%s]]', category, category, category)
else
item = string.format('%s[[Category:%s]]', category, category)
end
renderRow(tbl, cfg.name, item)
end
local function renderAmmo(tbl, cfg, stat, lang)
local ammo = nu.ammo(stat, lang)
local classSuffix
if aw.stringstarts(stat, 'special_') then
classSuffix = 'special'
else
classSuffix = stat
end
local item
if lang == 'ja' then
item = string.format(
'%s [[弾薬#%s|<span class="text-ammo text-ammo-%s">%s</span>]][[Category:%s]]',
iu.ammo(stat, { size = 24 }),
ammo,
classSuffix,
ammo,
ammo)
else
item = string.format(
'%s <span class="text-ammo text-ammo-%s">%s</span>[[Category:%s]]',
iu.ammo(stat, { size = 24 }),
classSuffix,
ammo,
ammo)
end
createCellInRow(tbl, cfg.name)
:addClass('cell-ammo')
:wikitext(item)
end
local function renderCost(tbl, cfg, stat)
if stat == nil then
return
end
local text = formatter:format(
aw.comma(stat[1]),
aw.comma(stat[2]),
aw.comma(stat[3]),
aw.comma(stat[4]),
'', ' - ')
renderRow(tbl, cfg.name, cfg.header .. text)
end
local function renderMode(tbl, cfg, stat)
local builder = require('Module:Utility/StringBuilder').new()
if stat.burst > 1 then
builder:appendFormat(cfg.burst, stat.burst)
builder:append(cfg.burst_category)
end
if stat.auto then
if not builder:isEmpty() then
builder:append(cfg.separator)
end
builder:append(cfg.auto, cfg.auto_category)
end
if stat.single then
if not builder:isEmpty() then
builder:append(cfg.separator)
end
builder:append(cfg.single, cfg.single_category)
end
renderRow(tbl, cfg.name, tostring(builder))
end
local function getDamageText(stat)
if aw.isNumber(stat.pellet) then
if aw.isNumberAndGreaterThanZero(stat.damage.charged) then
return string.format(
'<span class="text-type-number">%s</span> × %d → <span class="text-type-number">%s</span> × %d',
stat.damage.base,
stat.pellet,
stat.damage.charged,
stat.pellet)
else
return string.format(
'<span class="text-type-number">%s</span> × %d',
stat.damage.base,
stat.pellet)
end
else
if aw.isNumberAndGreaterThanZero(stat.damage.amped) then
return string.format(
'<span class="text-type-number">%s</span> <span class="text-separator">/</span> %s <span class="text-type-number">%s</span>',
stat.damage.base,
iu.item('シールドセル'),
stat.damage.amped)
elseif aw.isNumberAndGreaterThanZero(stat.damage.charged) then
return string.format(
'<span class="text-type-number">%s</span> → <span class="text-type-number">%s</span>',
stat.damage.base,
stat.damage.charged)
else
return string.format('<span class="text-type-number">%s</span>', stat.damage.base)
end
end
end
local function renderHeadRow(tbl, name, head, cfg, nolist)
local hlm1 = 0.2 + 0.8 * head
local hlm2 = 0.4 + 0.6 * head
local hlm3 = 0.5 + 0.5 * head
local opts = { align = 'left', footer = cfg.unit }
if nolist then
opts.class = 'no-list-style'
opts.headerAlign = 'right'
end
renderFormatRow(
tbl,
name,
nil, hlm1, hlm2, hlm3,
opts)
end
local function renderLegsRow(tbl, cfg, stat)
local text
if aw.isNumberAndGreaterThanZero(stat.legshot_charged) then
text = string.format(
'<span class="text-type-number">%s</span> → <span class="text-type-number">%s</span>%s',
stat.legshot,
stat.legshot_charged,
cfg.unit)
else
text = string.format(
'<span class="text-type-number">%s</span>%s',
stat.legshot,
cfg.unit)
end
tbl:tag('tr')
:tag('th')
:wikitext(cfg.legs)
:done()
:tag('td')
:attr('align', 'left')
:attr('colspan', 6)
:wikitext(text)
end
local DamageProto = {
damage = {
base = proto.NumberRange(1),
headshot = proto.NumberRange(1),
legshot = proto.NumberRange(0, 1),
},
}
local ShatterCapsProto = {
damage = {
base = proto.NumberRange(1),
headshot = proto.NumberRange(1),
legshot = proto.NumberRange(0, 1),
},
pellet = proto.NumberRange(1),
}
local damageHopups = {
{
name = 'anvil_receiver',
proto = DamageProto,
textclass = 'text-rarity-legendary',
dispclass = 'disp-rarity-legendary',
},
{
name = 'shatter_caps',
proto = ShatterCapsProto,
textclass = 'text-rarity-epic',
dispclass = 'disp-rarity-epic',
},
}
local function renderDamage(tbl, cfg, stat)
if not proto.validateTypes(stat, DamageProto) then
return
end
local cattext = string.format(cfg.head_category, stat.damage.headshot_charged or stat.damage.headshot)
local cell = createCellInRow(tbl, cfg.name)
cell:wikitext(cattext)
:wikitext(getDamageText(stat))
-- Headshot
local sprm = stat.damage.skullpiercer_rifling or 1
local hlmc = stat.damage.headshot_charged or 1
local intable =
--tbl:tag('tr'):tag('td'):attr('colspan', 2)
cell
:tag('table')
:addClass('condensedtable')
:addClass('listtable')
renderHeadRow(intable, cfg.head, stat.damage.headshot, cfg)
if sprm > 1 then
local nameS = iu.hopup('skullpiercer_rifling') .. ' '
renderHeadRow(intable, nameS, sprm, cfg, true)
elseif hlmc > 1 then
local nameC = '→ '
renderHeadRow(intable, nameC, hlmc, cfg, true)
end
-- Legsshot
renderLegsRow(intable, cfg, stat.damage)
-- [Hop-Up] Anvil Receiver & Shatter Caps
for _, v in ipairs(damageHopups) do
if proto.validateTypes(stat[v.name], v.proto) then
local intblS = cell:tag('div')
:addClass('tpl-weapon-inbox')
:addClass(v.dispclass)
:wikitext(iu.hopup(v.name) .. ' ')
:tag('span')
:addClass('text-rarity')
:addClass(v.textclass)
:wikitext(getDamageText(stat[v.name]))
:done()
:tag('table')
:addClass('condensedtable')
:addClass('listtable')
renderHeadRow(intblS, cfg.head, stat[v.name].damage.headshot, cfg)
renderLegsRow(intblS, cfg, stat[v.name].damage)
end
end
end
local function renderMultipleFirerateRow(intbl, name, cfg, rps, opts)
opts = opts or {}
renderFormatRow(
intbl,
name .. cfg.rps.name,
string.format(cfg.rps.format, aw.roundx(rps[1], 2)),
string.format(cfg.rps.format, aw.roundx(rps[2], 2)),
string.format(cfg.rps.format, aw.roundx(rps[3], 2)),
string.format(cfg.rps.format, aw.roundx(rps[4], 2)),
{ class = opts.rpsClass or '', separator = cfg.rps.separator, footer = cfg.rps.unit })
renderFormatRow(
intbl,
cfg.rpm.name,
string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[1], 1))),
string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[2], 1))),
string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[3], 1))),
string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[4], 1))),
{ class = opts.rpmClass and 'all-secondary text-smaller ' .. opts.rpmClass or 'all-secondary text-smaller', headerAlign = 'right', separator = cfg.rpm.separator, footer = cfg.rpm.unit })
end
local function renderVariableFirerateRow(intbl, name, cfg, rps1, rps2, opts)
opts = opts or {}
intbl
:tag('tr')
:addClassIf(type(opts.rarity) == 'string', 'row-rarity-first disp-rarity-' .. (opts.rarity or 'common'))
:addClassIf(type(opts.class) == 'string', opts.class)
:tag('th')
:wikitext(name)
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(string.format(cfg.rps.format, rps1))
:done()
:tag('td')
:wikitext(' → ')
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(string.format(cfg.rps.format, rps2))
:done()
:tag('td')
:wikitext(cfg.rps.unit)
:done()
:done()
:tag('tr')
:addClassIf(type(opts.rarity) == 'string', 'row-rarity-last disp-rarity-' .. (opts.rarity or 'common'))
:addClass('no-list-style')
:addClass('text-secondary')
:addClass('text-smaller')
:tag('th')
:attr('align', 'right')
:wikitext(cfg.rpm.name)
:done()
:tag('td')
:addClass('cell-type-number')
:wikitext(aw.comma(aw.roundx(60 * rps1, 1)))
:done()
:tag('td')
:wikitext(' → ')
:done()
:tag('td')
:addClass('cell-type-number')
:wikitext(aw.comma(aw.roundx(60 * rps2, 1)))
:done()
:tag('td')
:wikitext(cfg.rpm.unit)
end
local function renderFirerateRow(intbl, name, cfg, rps, opts)
opts = opts or {}
intbl:tag('tr')
:addClassIf(type(opts.rarity) == 'string', 'row-rarity-one disp-rarity-' .. (opts.rarity or 'common'))
:addClassIf(opts.class and type(opts.class) == 'string', opts.class)
:tag('th')
:wikitext(name)
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(string.format(cfg.rps.format, rps))
:done()
:tag('td')
:wikitext(cfg.rps.unit)
:done()
:tag('td')
:tag('small')
:addClass('text-secondary')
:wikitext(cfg.rpm.name)
:done()
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:tag('small')
:addClass('text-secondary')
:wikitext(aw.comma(0.1 * aw.round(600 * rps)))
:done()
:done()
:tag('td')
:tag('small')
:addClass('text-secondary')
:wikitext(cfg.rpm.unit)
end
local function renderFirerateCell(cell, cfg, rps, opts)
opts = opts or {}
opts.header = opts.header or ''
cell:wikitext(string.format(
opts.header .. '<span class="text-type-number">' .. cfg.rps.format .. '</span>' .. cfg.rps.unit .. '<span class="text-secondary"><small>(<span class="text-type-number">%s</span>' .. cfg.rpm.unit .. '</small></span>',
rps,
aw.comma(0.1 * aw.round(600 * rps))))
end
local MultipleNumberProto = {
proto.NumberRange(0),
proto.NumberRange(0),
proto.NumberRange(0),
proto.NumberRange(0),
}
local AnvilReceiverProto = {
firerate = {
single = proto.NumberRange(0),
},
}
local DeadeyesTempoWithChargeProto = {
firerate = {
single_charged = proto.NumberRange(0),
},
}
local DeadeyesTempoWithRechamberProto = {
firerate = {
single_rechamber = proto.NumberRange(0),
},
}
local function renderFirerate(tbl, cfg, stat)
local firerate = stat.firerate
if firerate == nil then
return
end
local mode = stat.mode
local cell = createCellInRow(tbl, cfg.name)
local rps
if mode.auto then
if mode.single then
local hasAnvil = proto.validateTypes(stat.anvil_receiver, AnvilReceiverProto)
if hasAnvil or firerate.auto ~= firerate.single then
local intbl
if firerate.auto ~= firerate.single then
intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('listtable')
local singleRPS
if aw.isNumberAndGreaterThanZero(firerate.single_rechamber) then
singleRPS = calcRechamberRPS(firerate)
else
singleRPS = firerate.single
end
renderFirerateRow(intbl, cfg.auto, cfg, firerate.auto)
renderFirerateRow(intbl, cfg.single, cfg, singleRPS)
else
intbl = cell:tag('table')
:addClass('condensedtable')
renderFirerateRow(intbl, '', cfg, firerate.auto)
end
if hasAnvil then
intbl:addClass('raritytable')
renderFirerateRow(intbl, iu.hopup('anvil_receiver') .. ' ', cfg, stat.anvil_receiver.firerate.single, { rarity = 'legendary' })
end
return
end
elseif mode.burst > 1 then
if type(firerate.auto) == 'table' then
local newcell = tbl:tag('tr')
:tag('td')
:attr('colspan', 2)
renderFirerateCell(newcell:tag('ul'):tag('li'), cfg, firerate.burst, { header = cfg.burst })
local intbl = newcell:tag('table')
:addClass('condensedtable')
:addClass('listtable')
local average = {
calcBurstAverageRPS(stat, firerate.burst_delay[1]),
calcBurstAverageRPS(stat, firerate.burst_delay[2]),
calcBurstAverageRPS(stat, firerate.burst_delay[3]),
calcBurstAverageRPS(stat, firerate.burst_delay[4]),
}
renderMultipleFirerateRow(intbl, cfg.burst_average, cfg, average, { rpsClass = 'no-list-style', rpmClass = 'no-list-style' })
renderMultipleFirerateRow(intbl, cfg.auto, cfg, firerate.auto, { rpmClass = 'no-list-style' })
else
local intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('listtable')
local average = calcBurstAverageRPS(stat)
renderFirerateRow(intbl, cfg.burst, cfg, firerate.burst)
renderFirerateRow(intbl, cfg.burst_average, cfg, average, { class = 'no-list-style' })
renderFirerateRow(intbl, cfg.auto, cfg, firerate.auto)
end
return
elseif aw.isNumberAndGreaterThanZero(firerate.auto_start) then
local intbl = cell:tag('table')
:addClass('condensedtable')
renderVariableFirerateRow(intbl, '', cfg, firerate.auto_start, firerate.auto)
if aw.isNumberAndGreaterThanZero(firerate.auto_start_turbocharger) then
intbl:addClass('raritytable')
renderVariableFirerateRow(intbl, iu.hopup('turbocharger') .. ' ', cfg, firerate.auto_start_turbocharger, firerate.auto, { rarity = 'legendary' })
end
return
end
rps = firerate.auto
elseif mode.single then
if mode.burst > 1 then
local intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('listtable')
local average = calcBurstAverageRPS(stat)
renderFirerateRow(intbl, cfg.burst, cfg, firerate.burst)
renderFirerateRow(intbl, cfg.burst_average, cfg, average, { class = 'no-list-style' })
local singleRPS
if aw.isNumberAndGreaterThanZero(firerate.single_rechamber) then
singleRPS = calcRechamberRPS(firerate)
else
singleRPS = firerate.single
end
renderFirerateRow(intbl, cfg.single, cfg, singleRPS)
return
end
if proto.validateTypes(firerate.single_rechamber, MultipleNumberProto) then
local calcRPS = {
calcRechamberRPS(firerate, firerate.single_rechamber[1]),
calcRechamberRPS(firerate, firerate.single_rechamber[2]),
calcRechamberRPS(firerate, firerate.single_rechamber[3]),
calcRechamberRPS(firerate, firerate.single_rechamber[4]),
}
local intbl = cell:tag('table'):addClass('condensedtable')
renderMultipleFirerateRow(intbl, '', cfg, calcRPS)
return
elseif aw.isNumberAndGreaterThanZero(firerate.single_charged) then
local minimum
local maximum
if aw.isNumberAndGreaterThanZero(firerate.single_charged_minimum) then
minimum = calcRechamberRPS(firerate, firerate.single_charged_minimum)
maximum = calcRechamberRPS(firerate, firerate.single_charged)
elseif aw.isNumberAndGreaterThanZero(firerate.single_rechamber) then
minimum = calcRechamberRPS(firerate, firerate.single_rechamber)
maximum = calcRechamberRPS(firerate, firerate.single_rechamber + firerate.single_charged)
else
minimum = firerate
maximum = calcRechamberRPS(firerate, firerate.single_charged)
end
local intbl = cell:tag('table'):addClass('condensedtable')
renderVariableFirerateRow(intbl, '', cfg, minimum, maximum)
if proto.validateTypes(stat.deadeyes_tempo, DeadeyesTempoWithChargeProto) then
intbl:addClass('raritytable')
local mintempo = calcRechamberRPS(firerate, aw.getAsNumber(stat.deadeyes_tempo.firerate.single_charged_minimum, 0))
local maxtempo = calcRechamberRPS(firerate, stat.deadeyes_tempo.firerate.single_charged)
renderVariableFirerateRow(intbl, iu.hopup('deadeyes_tempo') .. ' ', cfg, mintempo, maxtempo, { rarity = 'epic' })
end
return
elseif aw.isNumberAndGreaterThanZero(firerate.single_rechamber) then
if proto.validateTypes(stat.deadeyes_tempo, DeadeyesTempoWithRechamberProto) then
local normal = calcRechamberRPS(firerate, firerate.single_rechamber)
local tempo = calcRechamberRPS(firerate, stat.deadeyes_tempo.firerate.single_rechamber)
local intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('raritytable')
renderFirerateRow(intbl, '', cfg, normal)
renderFirerateRow(intbl, iu.hopup('deadeyes_tempo') .. ' ', cfg, tempo, { rarity = 'epic' })
return
else
rps = calcRechamberRPS(firerate)
end
else
rps = firerate.single
end
else
return
end
if type(rps) == 'table' then
local intbl = cell:tag('table'):addClass('condensedtable')
renderMultipleFirerateRow(intbl, '', cfg, rps)
else
renderFirerateCell(cell, cfg, rps)
end
end
local function renderProjectileSpeed(tbl, cfg, projectile_speed, projectile_speed_charged)
if projectile_speed == nil then
return
end
local text
if projectile_speed == math.huge then
text = cfg.hitscan
elseif projectile_speed_charged ~= nil then
text = string.format(
'<span class="text-type-number">%s</span> → <span class="text-type-number">%s</span>%s',
string.format(cfg.format, aw.comma(aw.roundx(0.0254 * projectile_speed, 2))),
string.format(cfg.format, aw.comma(aw.roundx(0.0254 * projectile_speed_charged, 2))),
cfg.unit)
else
text = string.format(
'<span class="text-type-number">%s</span>%s',
string.format(cfg.format, aw.comma(aw.roundx(0.0254 * projectile_speed, 2))),
cfg.unit)
end
renderRow(tbl, cfg.name, text)
end
local function renderDPS(tbl, cfg, stat, lang)
if stat.firerate == nil then
return
end
local sld = require('Module:Stat/Shield')['removelowprofile']
local node = require('Module:WeaponInfobox/DPS').renderDPS(stat, sld, lang)
createCellInRow(tbl, cfg.name)
tbl:tag('tr'):tag('td'):attr('colspan', 2):node(node)
end
local function renderMagazineRow(intbl, name, mag, rsvmag, cfg, opts)
opts = opts or {}
intbl:tag('tr')
:addClassIf(opts.class and type(opts.class) == 'string', opts.class)
:tag('th')
:wikitext(name)
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(mag)
:done()
:tag('td')
:wikitext(cfg.unit)
:done()
:tag('td')
:addClass('text-secondary')
:wikitext(' / ')
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(rsvmag == math.huge and cfg.infinity or rsvmag)
:done()
:tag('td')
:wikitext(cfg.unit)
end
local function renderMagazine(tbl, cfg, stat, isModdedLoaderAttachable)
local magazine = stat.magazine
local typename = type(magazine)
if typename == 'table' then
if isModdedLoaderAttachable then
local intable = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
renderFormatRow(
intable,
'',
magazine[1], magazine[2], magazine[3], magazine[4], { footer = cfg.units })
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
aw.round(1.15 * magazine[1]),
aw.round(1.15 * magazine[2]),
aw.round(1.15 * magazine[3]),
aw.round(1.15 * magazine[4]),
{ footer = cfg.units })
else
local text = formatter:format(magazine[1], magazine[2], magazine[3], magazine[4], cfg.units, ' - ')
renderRow(tbl, cfg.name, text)
end
elseif typename == 'number' then
local text
if magazine == math.huge then
if aw.isNumber(stat.overheat) and stat.firerate and stat.firerate.auto then
text = string.format(
'%s (<span class="text-type-number">%d</span>%s <span class="text-separator">/</span> %s <span class="text-type-number">%d</span>%s)',
cfg.infinity,
1 + math.floor(stat.overheat * stat.firerate.auto),
cfg.unit,
iu.passive('modded_loader'),
1 + math.floor(1.15 * stat.overheat * stat.firerate.auto),
cfg.unit)
else
text = cfg.infinity
end
elseif stat.rounds_per_shot and stat.rounds_per_shot.single and stat.rounds_per_shot.single > 1 then
local times = magazine / stat.rounds_per_shot.single
local timesText
if type(cfg.times.format) == 'table' then
if times > 2 then
timesText = string.format(cfg.times.format[3], times)
else
timesText = cfg.times.format[times]
end
else
timesText = string.format(cfg.times.format, times)
end
text = string.format(
'<span class="text-type-number">%d</span>%s <span class="text-secondary"><small>(%s)</small></span>',
magazine, cfg.unit, timesText)
elseif aw.isNumber(stat.magazine_reserve) then
if isModdedLoaderAttachable then
local intbl = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
renderMagazineRow(intbl, '', magazine, stat.magazine_reserve, cfg)
renderMagazineRow(intbl, iu.passive('modded_loader') .. ' ', aw.round(1.15 * magazine), stat.magazine_reserve, cfg)
return
else
text = string.format(
'<span class="text-type-number">%d</span>%s <span class="text-separator">/</span> <span class="text-type-number">%s</span>%s',
magazine,
cfg.unit,
stat.magazine_reserve == math.huge and cfg.infinity or stat.magazine_reserve,
cfg.unit)
end
else
text = string.format('<span class="text-type-number">%d</span>%s', magazine, cfg.unit)
end
renderRow(tbl, cfg.name, text)
end
end
local function renderReload(tbl, cfg, reload, attachments, ammo, isModdedLoaderAttachable)
if reload.full == nil then
return
end
local muls
if ammo == 'heavy' or ammo == 'special_heavy' then
muls = { level2 = 0.92, level3 = 0.87 }
else
muls = { level2 = 0.95, level3 = 0.9 }
end
local incompatible = not attachments.extended_mag_or_shotgun_bolt
if incompatible or ammo == 'shotgun' or aw.stringstarts(ammo, "special_") then
if reload.tactical ~= nil and reload.tactical ~= reload.full then
local tacticalText, fullText
if incompatible or ammo == 'special_sniper' then
tacticalText = tostring(reload.tactical)
fullText = tostring(reload.full)
else
tacticalText = tostring(muls.level3 * reload.tactical)
fullText = tostring(muls.level3 * reload.full)
end
local intable = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
:addClass('listtable')
renderFormatRow(
intable,
cfg.tactical.name .. ' ',
string.format(cfg.tactical.format, reload.tactical),
nil, nil, nil, { footer = cfg.tactical.unit })
if isModdedLoaderAttachable then
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
string.format(cfg.tactical.format, 0.75 * reload.tactical),
nil, nil, nil, { class = 'no-list-style', headerAlign = 'right', footer = cfg.tactical.unit })
end
renderFormatRow(
intable,
cfg.full.name .. ' ',
string.format(cfg.full.format, reload.full),
nil, nil, nil, { footer = cfg.full.unit })
if isModdedLoaderAttachable then
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
string.format(cfg.full.format, 0.75 * reload.full),
nil, nil, nil, { class = 'no-list-style', headerAlign = 'right', footer = cfg.full.unit })
end
elseif isModdedLoaderAttachable then
local time
if incompatible then
time = reload.full
else
time = muls.level3 * reload.full
end
local text = string.format(
cfg.full.format .. cfg.full.unit .. ' <span class="text-separator">/</span> %s ' .. cfg.full.format .. cfg.full.unit,
time,
iu.passive('modded_loader'),
0.75 * time)
renderRow(tbl, cfg.name, text)
else
local time
if incompatible or ammo == 'special_sniper' then
time = reload.full
else
time = muls.level3 * reload.full
end
renderRow(tbl, cfg.name, string.format(cfg.full.format, time) .. cfg.full.unit)
end
elseif reload.tactical ~= nil and reload.tactical ~= reload.full then
renderRow(tbl, cfg.name, '')
local intable = tbl:tag('tr')
:tag('td')
:attr('colspan', 2)
:tag('table')
:addClass('condensedtable')
:addClass('listtable')
renderFormatRow(
intable,
cfg.tactical.name .. ' ',
string.format(cfg.tactical.format, reload.tactical),
nil,
string.format(cfg.tactical.format, muls.level2 * reload.tactical),
string.format(cfg.tactical.format, muls.level3 * reload.tactical),
{ footer = cfg.tactical.unit })
if isModdedLoaderAttachable then
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
string.format(cfg.tactical.format, 0.75 * reload.tactical),
nil,
string.format(cfg.tactical.format, 0.75 * muls.level2 * reload.tactical),
string.format(cfg.tactical.format, 0.75 * muls.level3 * reload.tactical),
{ class = 'no-list-style', headerAlign = 'right', footer = cfg.tactical.unit })
end
renderFormatRow(
intable,
cfg.full.name .. ' ',
string.format(cfg.full.format, reload.full),
nil,
string.format(cfg.full.format, muls.level2 * reload.full),
string.format(cfg.full.format, muls.level3 * reload.full),
{ footer = cfg.full.unit })
if isModdedLoaderAttachable then
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
string.format(cfg.full.format, 0.75 * reload.full),
nil,
string.format(cfg.full.format, 0.75 * muls.level2 * reload.full),
string.format(cfg.full.format, 0.75 * muls.level3 * reload.full),
{ class = 'no-list-style', headerAlign = 'right', footer = cfg.full.unit })
end
else
local text = formatter:format(
string.format(cfg.full.format, reload.full),
nil,
string.format(cfg.full.format, muls.level2 * reload.full),
string.format(cfg.full.format, muls.level3 * reload.full),
cfg.full.unit, ' - ')
renderRow(tbl, cfg.name, text)
end
end
local function renderDraw(tbl, cfg, draw, quickdraw_holster, attachments, ammo)
if draw == nil then
return
end
local muls
if ammo == 'heavy' or ammo == 'special_heavy' then
muls = { level2 = 0.92, level3 = 0.87 }
else
muls = { level2 = 0.95, level3 = 0.9 }
end
local incompatible = not attachments.stock
if incompatible or aw.stringstarts(ammo, "special_") then
local time
if incompatible or ammo == 'special_sniper' then
time = draw
else
time = 0.75 * draw
end
local text
if quickdraw_holster > 0 then
text = string.format(
cfg.format .. cfg.unit .. ' <span class="text-separator">/</span> %s ' .. formatter:epic(cfg.format .. cfg.unit),
time,
iu.hopup('quickdraw_holster'),
quickdraw_holster * time)
else
text = string.format(cfg.format, time) .. cfg.unit
end
renderRow(tbl, cfg.name, text)
elseif quickdraw_holster > 0 then
local intable = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
renderFormatRow(
intable,
'',
string.format(cfg.format, draw),
string.format(cfg.format, 0.85 * draw),
string.format(cfg.format, 0.80 * draw),
string.format(cfg.format, 0.75 * draw),
{ footer = cfg.unit })
renderFormatRow(
intable,
iu.hopup('quickdraw_holster') .. ' ',
string.format(cfg.format, quickdraw_holster * draw),
string.format(cfg.format, 0.85 * quickdraw_holster * draw),
string.format(cfg.format, 0.80 * quickdraw_holster * draw),
string.format(cfg.format, 0.75 * quickdraw_holster * draw),
{ footer = cfg.unit })
else
local text = formatter:format(
string.format(cfg.format, draw),
string.format(cfg.format, 0.85 * draw),
string.format(cfg.format, 0.80 * draw),
string.format(cfg.format, 0.75 * draw),
cfg.unit, ' - ')
renderRow(tbl, cfg.name, text)
end
end
local function renderSpread(tbl, cfg, stat, lang)
local node = require('Module:WeaponInfobox/Spread').renderSpread(stat.spread, stat.quickdraw_holster and stat.quickdraw_holster.spread, lang)
createCellInRow(tbl, cfg.name)
tbl:tag('tr'):tag('td'):attr('colspan', 2):node(node)
end
local function createTable(cfg, stat, lang)
local isModdedLoaderAttachable = stat.category == 'light_machine_gun' or stat.ammo == 'minigun'
local tbl = mw.html.create('table')
renderReleaseDate(tbl, cfg.release, stat.release)
renderCategory(tbl, cfg.category, stat.category, lang)
renderAmmo(tbl, cfg.ammo, stat.ammo, lang)
renderCost(tbl, cfg.cost, stat.cost)
renderMode(tbl, cfg.mode, stat.mode)
renderDamage(tbl, cfg.damage, stat)
renderFirerate(tbl, cfg.firerate, stat)
renderProjectileSpeed(tbl, cfg.projectilespeed, stat.projectile_speed, stat.projectile_speed_charged)
renderMagazine(tbl, cfg.magazine, stat, isModdedLoaderAttachable)
if stat.time then
if stat.time.draw then
renderDraw(tbl, cfg.draw, stat.time.draw, stat.time.quickdraw_holster or 0, stat.attachments, stat.ammo)
end
if stat.time.reload then
renderReload(tbl, cfg.reload, stat.time.reload, stat.attachments, stat.ammo, isModdedLoaderAttachable)
end
end
renderDPS(tbl, cfg.dps, stat, lang)
renderSpread(tbl, cfg.spread, stat, lang)
return tbl
end
local function renderInfobox(args)
local lang = args and args.lang or 'ja'
local cfglang = cfg[lang]
local stat = mw.loadData('Module:Stat/Weapon')[args.name]
local div = mw.html.create('div')
:addClass('tpl-infobox-right')
:addClass('tpl-weapon')
if aw.stringstarts(stat.ammo, "special_") then
div:addClass('tpl-weapon-special')
else
div:addClass('tpl-weapon-' .. stat.ammo)
end
div:tag('div')
:addClass('tpl-weapon-header')
:wikitext(args.name .. iu.ammo(stat.ammo, { size = 40 }))
div:node(createTable(cfglang, stat, lang))
return div
end
function p._main(args, frame)
formatter = require('Module:Utility/Formatter').new(frame)
return tostring(renderInfobox(args))
end
function p.main(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
args = getArgs(frame)
return p._main(args, frame)
end
return p