🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:WeaponInfobox」の版間の差分
ナビゲーションに移動
検索に移動
(ディスラプター弾やハンマーポイント弾のダメージ表示の改善) |
(ボセックコンパウンドボウの場合のDPS表を表示しないように変更(新実装でのDPS表示を行うのに必要なパラメーターが整備されておらず、誤った値を表示するため)) |
||
800行目: | 800行目: | ||
end | end | ||
local function createTable(cfg, stat, lang, frame) | local function createTable(cfg, name, stat, lang, frame) | ||
local isSpecial = aw.stringstarts(stat.ammo, "special_") | local isSpecial = aw.stringstarts(stat.ammo, "special_") | ||
local isModdedLoaderAttachable = stat.category == 'light_machine_gun' or stat.ammo == 'minigun' | local isModdedLoaderAttachable = stat.category == 'light_machine_gun' or stat.ammo == 'minigun' | ||
816行目: | 816行目: | ||
renderMoveSpeed(tbl, cfg.movespeed, stat.move_speed, stat.move_speed_charged) | renderMoveSpeed(tbl, cfg.movespeed, stat.move_speed, stat.move_speed_charged) | ||
renderMagazine(tbl, cfg.magazine, stat, isSpecial, isModdedLoaderAttachable) | renderMagazine(tbl, cfg.magazine, stat, isSpecial, isModdedLoaderAttachable) | ||
if stat.firerate then | if stat.firerate and name ~= 'ボセックコンパウンドボウ' then | ||
renderDPS(tbl, cfg.dps, stat, lang) | renderDPS(tbl, cfg.dps, stat, lang) | ||
end | end | ||
845行目: | 845行目: | ||
:addClass('tpl-weapon-header') | :addClass('tpl-weapon-header') | ||
:wikitext(args.name .. iu.ammo(stat.ammo, { size = 40 })) | :wikitext(args.name .. iu.ammo(stat.ammo, { size = 40 })) | ||
div:node(createTable(cfglang, stat, lang, frame)) | div:node(createTable(cfglang, args.name, stat, lang, frame)) | ||
return div | return div | ||
end | end |
2021年9月11日 (土) 16:56時点における版
このモジュールについての説明文ページを モジュール:WeaponInfobox/doc に作成できます
require('Module:Utility/mw.html Extensions') local p = {} local cfg = mw.loadData('Module:WeaponInfobox/configuration') local Hopup = mw.loadData('Module:Stat/Hopup') local aw = require('Module:Utility/Library') local apex = require('Module:Utility/ApexLibrary') local iu = require('Module:Utility/Image') local inu = require('Module:Utility/ImageWithName') local nu = require('Module:Utility/Name') local proto = require('Module:Utility/Prototypes') local StringBuilder = require('Module:Utility/StringBuilder') local formatter -- lazily initialized local getArgs -- lazily initialized 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) createCellInRow(tbl, cfg.name) :addClass('cell-ammo') :wikitext(inu.ammo(stat, { lang = lang, size = 24 })) 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 appendMode(builder, cfg, stat, base) if stat.is_semi_auto or (stat.is_semi_auto == nil and base.is_semi_auto) then local burstCount = stat.burst_count or (base and base.burst_count) or 1 if aw.isNumberAndGreaterThanOrEqualToX(burstCount, 2) then builder:appendFormat(cfg.burst, burstCount) builder:append(cfg.burst_category) else builder:append(cfg.single, cfg.single_category) end else builder:append(cfg.auto, cfg.auto_category) end end local function renderMode(tbl, cfg, stat) local builder = StringBuilder.new() appendMode(builder, cfg, stat) if stat.altfire then builder:append(cfg.separator) appendMode(builder, cfg, stat.altfire, stat) end if stat.selectfire_receiver then builder:append(cfg.separator, '<span class="block-rarity disp-rarity-epic">', iu.hopup('selectfire_receiver'), ' ') appendMode(builder, cfg, stat.selectfire_receiver, stat) builder:append('</span>') end if stat.double_tap_trigger then builder:append(cfg.separator, '<span class="block-rarity disp-rarity-epic">', iu.hopup('double_tap_trigger'), ' ') appendMode(builder, cfg, stat.double_tap_trigger, stat) builder:append('</span>') end renderRow(tbl, cfg.name, tostring(builder)) end local HammerpointRoundsProto = { hammerpoint_rounds = { damage_unshielded_scale = proto.NumberRange(1), }, } local DisruptorRoundsProto = { disruptor_rounds = { damage_shield_scale = proto.NumberRange(1), }, } local function getDamageText(stat, root, isSpecial) local builder = StringBuilder.new() local rarity = isSpecial and 'heirloom' local damage, pellet if root then damage = stat.damage or root.damage pellet = stat.pellet or root.pellet or 1 else damage = stat.damage pellet = stat.pellet or 1 end if aw.isNumberAndGreaterThanOrEqualToX(pellet, 2) then builder:appendFormat( '<span class="text-type-number">%s</span> × %d', damage.base, pellet) if aw.isNumberAndGreaterThanZero(damage.charged) then builder:appendFormat( ' → <span class="text-type-number">%s</span> × %d', damage.charged, pellet) elseif proto.validateTypes(stat, HammerpointRoundsProto) then if not rarity then rarity = Hopup.hammerpoint_rounds.rarity end builder:appendFormat( ' → <span class="block-rarity disp-rarity-%s text-rarity text-rarity-%s">%s \'\'\'<span class="text-type-number">%s</span> × %d\'\'\'</span>', rarity, rarity, iu.hopup('hammerpoint_rounds', { rarity = rarity }), math.floor(damage.base * stat.hammerpoint_rounds.damage_unshielded_scale), pellet) end else if aw.isNumberAndGreaterThanZero(damage.amped) then builder:appendFormat( '<span class="text-type-number">%s</span> <span class="text-separator">/</span> %s <span class="text-type-number">%s</span>', damage.base, iu.item('シールドセル'), damage.amped) elseif aw.isNumberAndGreaterThanZero(damage.charged) then builder:appendFormat( '<span class="text-type-number">%s</span> → <span class="text-type-number">%s</span>', damage.base, damage.charged) elseif proto.validateTypes(stat, HammerpointRoundsProto) then if not rarity then rarity = Hopup.hammerpoint_rounds.rarity end builder:appendFormat( '<span class="text-type-number">%s</span> → <span class="block-rarity disp-rarity-%s text-rarity text-rarity-%s">%s \'\'\'<span class="text-type-number">%s</span>\'\'\'</span>', damage.base, rarity, rarity, iu.hopup('hammerpoint_rounds', { rarity = rarity }), math.floor(damage.base * stat.hammerpoint_rounds.damage_unshielded_scale)) elseif proto.validateTypes(stat, DisruptorRoundsProto) then if not rarity then rarity = Hopup.disruptor_rounds.rarity end builder:appendFormat( '<span class="block-rarity disp-rarity-%s text-rarity text-rarity-%s">%s \'\'\'<span class="text-type-number">%s</span>\'\'\'</span> → <span class="text-type-number">%s</span>', rarity, rarity, iu.hopup('disruptor_rounds', { rarity = rarity }), math.floor(damage.base * stat.disruptor_rounds.damage_shield_scale), damage.base) else builder:appendFormat('<span class="text-type-number">%s</span>', damage.base) end end return tostring(builder) end local function renderHeadRow(tbl, name, head, cfg, nolist) local opts = { align = 'left', footer = cfg.unit } if nolist then opts.class = 'no-list-style' opts.headerAlign = 'right' end renderFormatRow( tbl, name, nil, apex.calcHeadshotMultiplier(head, apex.HEAD_HLMLV1), apex.calcHeadshotMultiplier(head, apex.HEAD_HLMLV2), apex.calcHeadshotMultiplier(head, apex.HEAD_HLMLV3), opts) end local function renderHeadEffectiveRange(tbl, cfg, stat, root) local headDist = stat.damage_head_distance or root.damage_head_distance if aw.isNumberAndGreaterThanZero(headDist) then local text = string.format(cfg.head_effective_range, 0.0254 * headDist) tbl:tag('tr') :addClass('no-list-style') :tag('td') :attr('align', 'left') :attr('colspan', 7) :wikitext(text) end end local function renderLegsRow(tbl, cfg, stat, root) local legs = stat.damage_legs_scale or root.damage_legs_scale 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', legs, stat.legshot_charged, cfg.unit) else text = string.format( '<span class="text-type-number">%s</span>%s', legs, 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 = 'selectfire_receiver', proto = DamageProto, textclass = 'text-rarity-epic', dispclass = 'disp-rarity-epic', }, { 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, isSpecial) 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 .. getDamageText(stat, nil, isSpecial)) -- Headshot local head = stat.damage_head_scale or 1 local intable = cell:tag('table') :addClass('condensedtable') :addClass('listtable') renderHeadRow(intable, cfg.head, head, cfg) local hlmc = stat.damage.headshot_charged or 1 if hlmc > 1 then local nameC = '→ ' renderHeadRow(intable, nameC, hlmc, cfg, true) end local sprm = stat.damage.skullpiercer_rifling or 1 if sprm > 1 then local nameS = iu.hopup('skullpiercer_rifling') .. ' ' renderHeadRow(intable, nameS, sprm, cfg, true) end renderHeadEffectiveRange(intable, cfg, stat, stat) -- Legsshot renderLegsRow(intable, cfg, stat, stat) -- [Hop-Up] Selectfire Receiver, Anvil Receiver & Shatter Caps for _, v in ipairs(damageHopups) do local hopupStat = stat[v.name] if proto.validateTypes(hopupStat, v.proto) then local intblS = cell:tag('div') :addClass('tpl-weapon-inbox') :addClass(specialOnly and 'disp-rarity-heirloom' or v.dispclass) :wikitext(iu.hopup(v.name) .. ' ') :tag('span') :addClass('text-rarity') :addClass(specialOnly and 'text-rarity-heirloom' or v.textclass) :wikitext(getDamageText(hopupStat, stat)) :done() :tag('table') :addClass('condensedtable') :addClass('listtable') local head = hopupStat.damage_head_scale or stat.damage_head_scale or 1 renderHeadRow(intblS, cfg.head, head, cfg) renderHeadEffectiveRange(intblS, cfg, hopupStat, stat) renderLegsRow (intblS, cfg, hopupStat, stat) end end end local function renderFirerate(tbl, cfg, stat, lang) local cell = createCellInRow(tbl, cfg.name) local node, newcell = require('Module:WeaponInfobox/Firerate').renderFirerate(stat, lang) if newcell then tbl:tag('tr'):tag('td'):attr('colspan', 2):node(node) else cell:node(node) 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) 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 MultipleNumberProto = { proto.NumberRange(0), proto.NumberRange(0), proto.NumberRange(0), proto.NumberRange(0), } 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 moddedLoaderMagazine2 = apex.calcMagazineWithModdedLoader(magazine2) local moddedLoaderReserve = stat.magazine_reserve - (moddedLoaderMagazine2 - magazine2) local intbl = createCellInRow(tbl, cfg.name) :tag('table') :addClass('condensedtable') renderMagazineRow(intbl, '', magazine2, stat.magazine_reserve, cfg) renderMagazineRow(intbl, iu.passive('modded_loader') .. ' ', moddedLoaderMagazine2, moddedLoaderReserve, 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 }) local moddedLoaderMagazine = apex.calcMagazinesWithModdedLoader(magazine) renderFormatRow( intable, iu.passive('modded_loader') .. ' ', moddedLoaderMagazine[1], moddedLoaderMagazine[2], moddedLoaderMagazine[3], moddedLoaderMagazine[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 aw.isNumberAndGreaterThanZero(stat.firerate) 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), calcVirtualMagSize(stat.overheat[2], stat.firerate), calcVirtualMagSize(stat.overheat[3], stat.firerate), calcVirtualMagSize(stat.overheat[4], stat.firerate), { 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 text-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, true), calcVirtualMagSize(stat.overheat[2], stat.firerate, true), calcVirtualMagSize(stat.overheat[3], stat.firerate, true), calcVirtualMagSize(stat.overheat[4], stat.firerate, 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 text-secondary text-smaller', headerAlign = 'right', separator = ' - ', footer = cfg.seconds.unit }) end return elseif aw.isNumberAndGreaterThanZero(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), cfg.unit, iu.passive('modded_loader'), 1 + math.floor(1.15 * stat.overheat * stat.firerate), cfg.unit) else text = cfg.infinity end else text = cfg.infinity end elseif aw.isNumberAndGreaterThanX(stat.ammo_per_shot, 1) then local times = magazine / stat.ammo_per_shot 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 and stat.anvil_receiver.spread then local node2 = Spread.renderSpread(stat.anvil_receiver.spread, nil, lang) if frame then local tabContent = string.format( '{{#tab:%s|%s}}{{#tab:%s|%s}}', cfg.normal, tostring(node), cfg.anvil_receiver, tostring(node2)) tbl:tag('tr') :tag('td') :attr('colspan', 2) :wikitext(frame:extensionTag { name = 'tabs', content = tabContent, args = { class = 'tabs-intable' }}) else tbl:tag('tr') :tag('td') :attr('colspan', 2) :tag('b') :wikitext(cfg.normal) :done() :node(node) :tag('b') :wikitext(cfg.anvil_receiver) :done() :node(node2) end elseif stat.spread_charged then local node2 = Spread.renderSpread(stat.spread_charged , nil, lang) if frame then local tabContent = string.format( '{{#tab:%s|%s}}{{#tab:%s|%s}}', cfg.normal, tostring(node), cfg.full_charge, tostring(node2)) tbl:tag('tr') :tag('td') :attr('colspan', 2) :wikitext(frame:extensionTag { name = 'tabs', content = tabContent, args = { class = 'tabs-intable' }}) else tbl:tag('tr') :tag('td') :attr('colspan', 2) :tag('b') :wikitext(cfg.normal) :done() :node(node) :tag('b') :wikitext(cfg.full_charge) :done() :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 stat.anvil_receiver and stat.anvil_receiver.spread and 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, name, 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) renderDamage(tbl, cfg.damage, stat, isSpecial) if stat.firerate then renderFirerate(tbl, cfg.firerate, stat, lang) end 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) if stat.firerate and name ~= 'ボセックコンパウンドボウ' then renderDPS(tbl, cfg.dps, stat, lang) end 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, args.name, 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