| 🌟 | 現在、 鉄壁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(type(opts.class) == 'string', opts.class)
:addClassIf(type(opts.rarity) == 'string', 'row-rarity-one disp-rarity-' .. (opts.rarity or 'common'))
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 })
:tag('span')
:addClass('text-rarity')
:addClass('text-rarity-common')
:wikitext(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 })
:tag('span')
:addClass('text-rarity')
:addClass('text-rarity-rare')
:wikitext(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 })
:tag('span')
:addClass('text-rarity')
:addClass('text-rarity-epic')
:wikitext(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, ammo)
if stat == nil or aw.stringstarts(ammo, 'special_') 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
-- Amped firerate
elseif aw.isNumberAndGreaterThanZero(firerate.auto_amped) then
local intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('raritytable')
renderFirerateRow(intbl, '', cfg, firerate.auto)
renderFirerateRow(intbl, iu.grenade('テルミットグレネード') .. ' ', cfg, firerate.auto_amped, { rarity = 'common' })
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 not aw.isNumberAndGreaterThanZero(projectile_speed) then
return
end
local text
if projectile_speed == math.huge then
text = cfg.hitscan
elseif aw.isNumberAndGreaterThanZero(move_speed_charged) 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 renderMoveSpeed(tbl, cfg, move_speed, move_speed_charged)
if not aw.isNumberAndGreaterThanZero(move_speed) then
return
end
local text
if aw.isNumberAndGreaterThanZero(move_speed_charged) then
text = string.format(
'<span class="text-type-number">%s</span> → <span class="text-type-number">%s</span>%s',
string.format(cfg.format, 100 * (move_speed - 1)),
string.format(cfg.format, 100 * (move_speed_charged - 1)),
cfg.unit)
else
text = string.format(
'<span class="text-type-number">%s</span>%s',
string.format(cfg.format, 100 * (move_speed - 1)),
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 calcVirtualMagSize(overheat, firerate, moddedLoader)
if moddedLoader then
return math.ceil(1.15 * overheat * firerate)
else
return math.ceil(overheat * firerate)
end
end
local function renderMagazine(tbl, cfg, stat, isSpecial, isModdedLoaderAttachable)
local magazine = stat.magazine
local typename = type(magazine)
local text
-- 物資投下武器
if isSpecial or stat.ammo == 'minigun' then
local magazine2
if typename == 'table' then
magazine2 = magazine[4]
else
magazine2 = magazine
end
if aw.isNumberAndGreaterThanZero(stat.magazine_reserve) then
if isModdedLoaderAttachable then
local intbl = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
renderMagazineRow(intbl, '', magazine2, stat.magazine_reserve, cfg)
renderMagazineRow(intbl, iu.passive('modded_loader') .. ' ', aw.round(1.15 * magazine2), 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',
magazine2,
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', magazine2, cfg.unit)
end
-- 拡張マガジンあり
elseif 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],
{ separator = ' - ', footer = cfg.unit })
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]),
{ separator = ' - ', footer = cfg.unit })
return
-- Boosted Loader
elseif stat.boosted_loader and proto.validateTypes(stat.boosted_loader.magazine, MultipleNumberProto) then
local intable = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
:addClass('raritytable')
renderFormatRow(
intable,
'',
magazine[1], magazine[2], magazine[3], magazine[4],
{ separator = ' - ', footer = cfg.unit })
renderFormatRow(
intable,
iu.hopup('boosted_loader') .. ' ',
stat.boosted_loader.magazine[1],
stat.boosted_loader.magazine[2],
stat.boosted_loader.magazine[3],
stat.boosted_loader.magazine[4],
{ rarity = 'legendary', separator = ' - ', footer = cfg.unit })
return
else
text = formatter:format(magazine[1], magazine[2], magazine[3], magazine[4], cfg.unit, ' - ')
end
-- 拡張マガジンなし
elseif typename == 'number' then
if magazine == math.huge then
if stat.firerate and stat.firerate.auto then
if proto.validateTypes(stat.overheat, MultipleNumberProto) then
local intable = createCellInRow(tbl, cfg.name)
:tag('table')
:addClass('condensedtable')
renderFormatRow(
intable,
'',
calcVirtualMagSize(stat.overheat[1], stat.firerate.auto),
calcVirtualMagSize(stat.overheat[2], stat.firerate.auto),
calcVirtualMagSize(stat.overheat[3], stat.firerate.auto),
calcVirtualMagSize(stat.overheat[4], stat.firerate.auto),
{ separator = ' - ', footer = cfg.unit })
renderFormatRow(
intable,
cfg.seconds.name,
string.format(cfg.seconds.format, stat.overheat[1]),
string.format(cfg.seconds.format, stat.overheat[2]),
string.format(cfg.seconds.format, stat.overheat[3]),
string.format(cfg.seconds.format, stat.overheat[4]),
{ class = 'no-list-style all-secondary text-smaller', headerAlign = 'right', separator = ' - ', footer = cfg.seconds.unit })
if isModdedLoaderAttachable then
renderFormatRow(
intable,
iu.passive('modded_loader') .. ' ',
calcVirtualMagSize(stat.overheat[1], stat.firerate.auto, true),
calcVirtualMagSize(stat.overheat[2], stat.firerate.auto, true),
calcVirtualMagSize(stat.overheat[3], stat.firerate.auto, true),
calcVirtualMagSize(stat.overheat[4], stat.firerate.auto, true),
{ separator = ' - ', footer = cfg.unit })
renderFormatRow(
intable,
cfg.seconds.name,
string.format(cfg.seconds.format, 1.15 * stat.overheat[1]),
string.format(cfg.seconds.format, 1.15 * stat.overheat[2]),
string.format(cfg.seconds.format, 1.15 * stat.overheat[3]),
string.format(cfg.seconds.format, 1.15 * stat.overheat[4]),
{ class = 'no-list-style all-secondary text-smaller', headerAlign = 'right', separator = ' - ', footer = cfg.seconds.unit })
end
return
elseif aw.isNumber(stat.overheat) 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
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)
else
text = string.format('<span class="text-type-number">%d</span>%s', magazine, cfg.unit)
end
end
renderRow(tbl, cfg.name, text)
end
local function renderDuration(tbl, cfg, stat, lang)
local node, isSimple = require('Module:WeaponInfobox/Duration').renderDuration(stat, lang)
local cell = createCellInRow(tbl, cfg.name)
if isSimple then
cell:node(node)
else
tbl:tag('tr'):tag('td'):attr('colspan', 2):node(node)
end
end
local function renderSpread(tbl, cfg, stat, lang, frame)
local Spread = require('Module:WeaponInfobox/Spread')
local node = Spread.renderSpread(stat.spread, stat.quickdraw_holster and stat.quickdraw_holster.spread, lang)
local cell = createCellInRow(tbl, cfg.name)
if node.tagName == 'span' then
cell:node(node)
elseif stat.anvil_receiver.spread then
local node2 = Spread.renderSpread(stat.anvil_receiver.spread, nil, lang)
if frame then
local text = frame:callParserFunction(
'#tab',
string.format('%s,%s', cfg.normal, cfg.anvil_receiver),
tostring(node),
tostring(node2))
tbl:tag('tr')
:tag('td')
:attr('colspan', 2)
:wikitext(frame:callParserFunction('#tag:tabs', { text, class = tabs-intable }))
else
tbl:tag('tr')
:tag('td')
:attr('colspan', 2)
:tag('b')
:wikitext(cfg.normal)
:node(node)
:done()
:tag('b')
:wikitext(cfg.anvil_receiver)
:node(node2)
end
else
tbl:tag('tr'):tag('td'):attr('colspan', 2):node(node)
end
end
local function renderSpreadDecayRow(intbl, name, cfg, spread, opts)
opts = opts or {}
intbl:tag('tr')
:addClassIf(type(opts.rarity) == 'string', 'row-rarity-one disp-rarity-' .. (opts.rarity or 'common'))
:tag('th')
:wikitext(name)
:done()
:tag('td')
:addClass('cell-type-number')
:attr('align', 'right')
:wikitext(string.format(cfg.rate.format, spread.decay_rate))
:done()
:tag('td')
:wikitext(cfg.rate.unit)
:done()
:tag('td')
:addClass('text-smaller')
:wikitext(cfg.delay.name)
:done()
:tag('td')
:addClass('cell-type-number')
:addClass('text-smaller')
:attr('align', 'right')
:wikitext(string.format(cfg.delay.format, spread.decay_delay))
:done()
:tag('td')
:addClass('text-smaller')
:wikitext(cfg.delay.unit)
end
local function renderSpreadDecay(tbl, cfg, stat)
if not (aw.isNumberAndGreaterThanZero(stat.spread.decay_rate) and aw.isNumberAndGreaterThanZero(stat.spread.decay_delay)) then
return
end
local cell = createCellInRow(tbl, cfg.name)
-- [Hop-up] Anvil Receiver
if aw.isNumberAndGreaterThanZero(stat.anvil_receiver.spread.decay_rate) and aw.isNumberAndGreaterThanZero(stat.anvil_receiver.spread.decay_delay) then
local intbl = cell:tag('table')
:addClass('condensedtable')
:addClass('raritytable')
renderSpreadDecayRow(
intbl,
'',
cfg,
stat.spread)
renderSpreadDecayRow(
intbl,
iu.hopup('anvil_receiver') .. ' ',
cfg,
stat.anvil_receiver.spread,
{ rarity = 'legendary' })
else
local text = string.format(cfg.format, stat.spread.decay_rate, stat.spread.decay_delay)
cell:wikitext(text)
end
end
local function createTable(cfg, stat, lang, frame)
local isSpecial = aw.stringstarts(stat.ammo, "special_")
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, stat.ammo)
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)
renderMoveSpeed(tbl, cfg.movespeed, stat.move_speed, stat.move_speed_charged)
renderMagazine(tbl, cfg.magazine, stat, isSpecial, isModdedLoaderAttachable)
renderDPS(tbl, cfg.dps, stat, lang)
if stat.time then
renderDuration(tbl, cfg.duration, stat, lang)
end
if stat.spread then
renderSpread(tbl, cfg.spread, stat, lang, frame)
renderSpreadDecay(tbl, cfg.spreaddecay, stat)
end
return tbl
end
local function renderInfobox(args, frame)
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, frame))
return div
end
function p._main(args, frame)
formatter = require('Module:Utility/Formatter').new(frame)
return tostring(renderInfobox(args, frame))
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