🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁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 renderRow(tbl, cfg.name, item) 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, rarityclass = 'text-rarity-legendary', inboxclass = 'tpl-weapon-inbox-legendary', }, { name = 'shatter_caps', proto = ShatterCapsProto, rarityclass = 'text-rarity-epic', inboxclass = 'tpl-weapon-inbox-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.inboxclass) :wikitext(iu.hopup(v.name) .. ' ') :tag('span') :addClass('text-rarity') :addClass(v.rarityclass) :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, 0.01 * aw.round(100 * rps[1])), string.format(cfg.rps.format, 0.01 * aw.round(100 * rps[2])), string.format(cfg.rps.format, 0.01 * aw.round(100 * rps[3])), string.format(cfg.rps.format, 0.01 * aw.round(100 * rps[4])), { class = opts.rpsClass or '', separator = cfg.rps.separator, footer = cfg.rps.unit }) renderFormatRow( intbl, cfg.rpm.name, string.format(cfg.rpm.format, aw.comma(0.1 * aw.round(600 * rps[1]))), string.format(cfg.rpm.format, aw.comma(0.1 * aw.round(600 * rps[2]))), string.format(cfg.rpm.format, aw.comma(0.1 * aw.round(600 * rps[3]))), string.format(cfg.rpm.format, aw.comma(0.1 * aw.round(600 * rps[4]))), { class = opts.rpmClass and 'all-secondary ' .. opts.rpmClass or 'all-secondary', 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 row-rarity-first row-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 row-rarity-last row-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(0.1 * aw.round(600 * rps1))) :done() :tag('td') :attr('align', 'right') :wikitext(' → ') :done() :tag('td') :addClass('cell-type-number') :wikitext(aw.comma(0.1 * aw.round(600 * rps2))) :done() :tag('td') :wikitext(cfg.rpm.unit) end local function renderFirerateRow(intbl, name, cfg, rps, 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(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), single_charged_minimum = 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 = tbl:tag('tr'):tag('td'):attr('colspan', 2):tag('table') :addClass('condensedtable') :addClass('listtable') renderFirerateRow(intbl, cfg.auto_single, cfg, firerate.auto) end if hasAnvil then renderFirerateRow(intbl, iu.hopup('anvil_receiver'), cfg, stat.anvil_receiver.firerate.single) 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 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 maximum = calcRechamberRPS(firerate, firerate.single_charged) if aw.isNumberAndGreaterThanZero(firerate.single_charged_minimum) then local minimum = calcRechamberRPS(firerate, firerate.single_charged_minimum) local intbl = cell:tag('table'):addClass('condensedtable') renderVariableFirerateRow(intbl, '', cfg, minimum, maximum) if proto.validateTypes(stat.deadeyes_tempo, DeadeyesTempoWithChargeProto) then local mintempo = calcRechamberRPS(firerate, stat.deadeyes_tempo.firerate.single_charged_minimum) local maxtempo = calcRechamberRPS(firerate, stat.deadeyes_tempo.firerate.single_charged) renderVariableFirerateRow(intbl, iu.hopup('deadeyes_tempo') .. ' ', cfg, mintempo, maxtempo, { rarity = 'epic' }) end return else rps = maximum end elseif aw.isNumberAndGreaterThanZero(firerate.single_rechamber) then if stat.deadeyes_tempo and 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('listtable') renderFirerateRow(intbl, '', cfg, normal) renderFirerateRow(intbl, iu.hopup('deadeyes_tempo') .. ' ', cfg, tempo) return else rps = 1 / (1 / firerate.single + firerate.single_rechamber) 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 renderRowDPS(tbl, name, leg, body, head, skullpiercer, tag) tag = tag or 'td' local row = tbl:tag('tr') row:tag('th'):wikitext(name) if leg == '' then row:tag(tag) :attr('align', 'center') :addClass('disabled') :wikitext('–') elseif leg ~= nil and leg ~= body then row:tag(tag):wikitext(leg) end row :tag(tag):wikitext(body):done() :tag(tag):wikitext(head) if skullpiercer ~= nil then row:tag(tag):wikitext(skullpiercer) end end local function toDPSText(dps) return string.format("%.1f", dps) end local function renderDPSTable(cell, name, pellet, base, damages, firerate, useRound) local headDamage = aw.round(damages.headshot * base) local legDamage = aw.round(damages.legshot * base) local skullpiercer = damages.skullpiercer_rifling local selectiveRound = useRound and aw.round or aw.roundover local skullpiercerHeader = nil local commonSkullpiercerDPS = nil local lowprofileSkullpiercerDPS = nil local fortifiedSkullpiercerDPS = nil if skullpiercer ~= nil then skullpiercerHeader = iu.hopup('skullpiercer_rifling') local skullpiercerDamage = aw.round(skullpiercer * base) commonSkullpiercerDPS = toDPSText(pellet * skullpiercerDamage * firerate) lowprofileSkullpiercerDPS = toDPSText(pellet * selectiveRound(1.05 * skullpiercerDamage) * firerate) fortifiedSkullpiercerDPS = toDPSText(pellet * aw.round(0.85 * skullpiercerDamage) * firerate) end if type(firerate) == 'table' then firerate = firerate[1] end local intable = cell:tag('table') :addClass('intable') :addClass('numbertable') local lowprofileLegDamagePlaceholder if damages.legshot == 1 then lowprofileLegDamagePlaceholder = nil renderRowDPS(intable, name, nil, '胴', '頭', skullpiercerHeader, 'th') else lowprofileLegDamagePlaceholder = '' renderRowDPS(intable, name, '脚', '胴', '頭', skullpiercerHeader, 'th') end renderRowDPS( intable, '通常', toDPSText(pellet * legDamage * firerate), toDPSText(pellet * base * firerate), toDPSText(pellet * headDamage * firerate), commonSkullpiercerDPS) renderRowDPS( intable, '小柄', lowprofileLegDamagePlaceholder, toDPSText(pellet * selectiveRound(1.05 * base, useRound) * firerate), toDPSText(pellet * selectiveRound(1.05 * headDamage, useRound) * firerate), lowprofileSkullpiercerDPS) renderRowDPS( intable, '鉄壁', toDPSText(pellet * aw.round(0.85 * legDamage) * firerate), toDPSText(pellet * aw.round(0.85 * base) * firerate), toDPSText(pellet * aw.round(0.85 * headDamage) * firerate), fortifiedSkullpiercerDPS) end local function renderDPS(tbl, name, stat) if stat.firerate == nil then return end local damage = stat.damage.base renderRow(tbl, name, '') local pellet = stat.pellet or 1 local useRound = stat.damage.round or false local cell = tbl:tag('tr'):tag('td'):attr('colspan', 2) if type(damage) == 'table' then for _, damage in ipairs(damage) do if stat.mode.single then renderDPSTable( cell, '', pellet, damage, stat.damage, stat.firerate.single, useRound) end end else if stat.mode.burst and stat.mode.burst > 1 then local average if type(stat.firerate.burst_delay) == 'table' then average = calcBurstAverageRPS(stat, stat.firerate.burst_delay[1]) else average = calcBurstAverageRPS(stat) end renderDPSTable( cell, '', pellet, stat.damage.base, stat.damage, average, useRound) end if stat.mode.auto then renderDPSTable( cell, '', pellet, stat.damage.base, stat.damage, stat.firerate.auto, useRound) end if stat.mode.single and stat.firerate.auto ~= stat.firerate.single then renderDPSTable( cell, '', pellet, stat.damage.base, stat.damage, stat.firerate.single, useRound) end if stat.damage.anvil_receiver and stat.firerate.anvil_receiver then renderDPSTable( cell, iu.hopup('anvil_receiver'), pellet, stat.damage.anvil_receiver.base, stat.damage.anvil_receiver, stat.firerate.anvil_receiver, useRound) end end 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) 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, 'DPS', stat) 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