🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:DamageTable」の版間の差分
ナビゲーションに移動
検索に移動
(スカルピアサーライフリングのフォーマット指定の簡略化とヘッドショット倍率が1倍以下のケースに対処) |
(TTKモジュール Module:Apex/TTKCalculator を変数として定義) タグ: 差し戻し済み |
||
6行目: | 6行目: | ||
local apex = require('Module:Utility/ApexLibrary') | local apex = require('Module:Utility/ApexLibrary') | ||
local STKCalculator = require('Module:Apex/STKCalculator') | local STKCalculator = require('Module:Apex/STKCalculator') | ||
local TTKCalculator = require('Module:Apex/TTKCalculator') | |||
local getArgs -- lazily initialized | local getArgs -- lazily initialized | ||
354行目: | 355行目: | ||
end | end | ||
local ttkc = | local ttkc = TTKCalculator.new(firerate, magazine, reload, { | ||
raise = args.raise, | raise = args.raise, | ||
}) | }) |
2021年8月12日 (木) 14:12時点における版
このモジュールについての説明文ページを モジュール:DamageTable/doc に作成できます
require('Module:Utility/mw.html Extensions') local p = {} local aw = require('Module:Utility/Library') local apex = require('Module:Utility/ApexLibrary') local STKCalculator = require('Module:Apex/STKCalculator') local TTKCalculator = require('Module:Apex/TTKCalculator') local getArgs -- lazily initialized local function convertHslToRgb(hue, saturation, lightness) hue = math.max(0, math.min(1, hue)) saturation = math.max(0, math.min(1, saturation)) lightness = math.max(0, math.min(1, lightness)) if saturation == 0 then return lightness, lightness, lightness else local function to(p, q, t) if t < 0 then t = t + 1 end if t > 1 then t = t - 1 end if t < 1/6 then return p + (q - p) * 6 * t elseif t < 3/6 then return q elseif t < 4/6 then return p + (q - p) * (2/3 - t) * 6 else return p end end local q if lightness < 0.5 then q = lightness * (1 + saturation) else q = lightness + saturation - lightness * saturation end local p = 2 * lightness - q return to(p, q, hue + 1/3), to(p, q, hue), to(p, q, hue - 1/3) end end local function getColorAsString(hue) local r, g, b = convertHslToRgb(hue, 0.91, 0.89) return string.format('#%02X%02X%02X', 255 * r, 255 * g, 255 * b) end local function getShotCount(part, health, shield, info, gunshield) local damages = apex.calcShotCount(info.damage, part, info.mul, health, shield, gunshield or 0, { ampedCover = info.amped, beamdamage = info.beamdamage, beamticks = info.ticks, disruptorRounds = info.disruptor, hammerpointRounds = info.hammerpoint, gunshieldBleedthrough = info.bleedthrough, passthrough = info.passthrough, pellets = info.pellet, round = info.useRound, }) return #damages, damages end local function renderHeader(tbl, mul, colspan, shields, res) tbl:tag('tr') :tag('th') :attr('colspan', colspan) :attr('rowspan', 2) :wikitextIf( mul == 1, res.targets.caption, function() return string.format(res.targets.caption_format, mul) end) :done() :tag('th') :attr('rowspan', 2) :wikitext(res.damages.caption) :done() :tag('th') :attr('colspan', #shields) :wikitext(res.shotstokill) local row = tbl:tag('tr') for _, shield in ipairs(shields) do row:tag('th') :attrIf( shield.tooltip ~= nil, { ['data-tooltip'] = shield.tooltip }) :wikitext(shield.label) end end local function renderCell(row, part, health, shield, info, gunshield) local shotCount, damages = getShotCount(part, health, shield, info, gunshield) local ratio = (shotCount - info.minCount) / (info.maxCount - info.minCount) local tooltip = { aw.stringifyRepeatingArray(damages, '→') } if info.ttkCalculator then local template = '<tr><th>%s </th><td class="cell-type-number" style="font-weight:bold">%d</td><td> ミリ秒</td></tr>' local ttkc = info.ttkCalculator local ttk0 = aw.round(1000 * ttkc:getAsLevel(shotCount, 0)) local ttk1 = aw.round(1000 * ttkc:getAsLevel(shotCount, 1)) local ttk2 = aw.round(1000 * ttkc:getAsLevel(shotCount, 2)) local ttk3 = aw.round(1000 * ttkc:getAsLevel(shotCount, 3)) if ttk2 ~= ttk3 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') if ttk0 == ttk1 then table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) else table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) end table.insert(tooltip, string.format(template, 'Lv.3', ttk3)) table.insert(tooltip, '</table>') elseif ttk1 ~= ttk2 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') if ttk0 == ttk1 then table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) else table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) end table.insert(tooltip, string.format(template, 'Lv.2, 3', ttk2)) table.insert(tooltip, '</table>') elseif ttk0 ~= ttk1 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1, 2, 3', ttk1)) table.insert(tooltip, '</table>') else table.insert(tooltip, string.format('<br>キルタイム: <span class="text-style-number" style="font-weight:bold">%d</span> ミリ秒', ttk0)) end end row:tag('td') :attr('data-tooltip', table.concat(tooltip)) :css('background-color', getColorAsString(0.85 * ratio)) :wikitext(shotCount) end local function renderHeaderCell(row, name, tooltip, rowinfo) for i = 1, #rowinfo do local cellinfo = rowinfo[i] local colspan = cellinfo.colspan or 1 local rowspan = cellinfo.rowspan or 1 local cell = row:tag('th') if colspan > 1 then cell:attr('colspan', colspan) end if rowspan > 1 then cell:attr('rowspan', rowspan) end if cellinfo.breaktop then cell:css('border-top', '0 none') end if cellinfo.breakbottom then cell:css('border-bottom', '0 none') end if cellinfo.verticalAlign then cell:css('vertical-align', cellinfo.verticalAlign) end if i == #rowinfo then if tooltip ~= nil then cell:attr('data-tooltip', tooltip) end cell:wikitext(name) elseif cellinfo.content then cell:wikitext(cellinfo.content) else cell:wikitext(' ') end end end local function renderRow(tbl, name, tooltip, part, weaponinfo, rowinfo, res, gunshield) local row = tbl:tag('tr') renderHeaderCell(row, name, tooltip, rowinfo) local opts = { ampedCover = weaponinfo.amped, charged = weaponinfo.charged, disruptorRounds = weaponinfo.disruptor, hammerpointRounds = weaponinfo.hammerpoint, gunshieldBleedthrough = weaponinfo.bleedthrough, passthrough = weaponinfo.passthrough, round = weaponinfo.useRound, } local damage if gunshield then damage = apex.calcDamage(weaponinfo.damage, 1, 1, { ampedCover = weaponinfo.amped, charged = weaponinfo.charged, passthrough = weaponinfo.passthrough, round = weaponinfo.useRound, }) else damage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, opts) end local text if not gunshield and weaponinfo.disruptor > 1 then local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, { ampedCover = weaponinfo.amped, charged = weaponinfo.charged, passthrough = weaponinfo.passthrough, round = weaponinfo.useRound, }) if weaponinfo.pellet > 1 then text = string.format( res.damages.pelletsWithDisruptor, damage * weaponinfo.pellet, damage, weaponinfo.pellet, defaultDamage * weaponinfo.pellet) else text = string.format(res.damages.disruptor, damage, defaultDamage) end elseif not gunshield and weaponinfo.hammerpoint > 1 then local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, { ampedCover = weaponinfo.amped, charged = weaponinfo.charged, passthrough = weaponinfo.passthrough, round = weaponinfo.useRound, }) if weaponinfo.pellet > 1 then text = string.format( res.damages.pelletsWithHammerpoint, defaultDamage * weaponinfo.pellet, damage * weaponinfo.pellet, damage, weaponinfo.pellet) else text = string.format(res.damages.hammerpoint, defaultDamage, damage) end elseif weaponinfo.pellet > 1 then text = string.format( res.damages.pellets, damage * weaponinfo.pellet, damage, weaponinfo.pellet) elseif weaponinfo.ticks > 1 then local beamdamage = apex.calcDamageFromPartAndPassive(weaponinfo.beamdamage, part, weaponinfo.mul, opts) local alldamage = beamdamage * weaponinfo.ticks + damage text = string.format( res.damages.ticks, alldamage, beamdamage, weaponinfo.ticks, damage) else text = tostring(damage) end row:tag('td'):wikitext(text) for _, shield in ipairs(weaponinfo.shields) do renderCell(row, part, shield.health, shield.shield, weaponinfo, gunshield) end end local function getTTKCalculator(args) if args.rps <= 0 then return nil end -- 射撃レート local firerate if args.rpsratio1 > 1 then if args.rpsratio2 > args.rpsratio1 then if args.rpsratio3 > args.rpsratio2 then firerate = { args.rps, args.rpsratio1 * args.rps, args.rpsratio2 * args.rps, args.rpsratio3 * args.rps, } else local rps2 = args.rpsratio2 * args.rps firerate = { args.rps, args.rpsratio1 * args.rps, rps2, rps2, } end else local rps1 = args.rpsratio1 * args.rps firerate = { args.rps, rps1, rps1, rps1, } end else firerate = args.rps end -- 装填数 local magazine if args.extmag0 > 0 then if args.extmag1 > args.extmag0 then if args.extmag2 > args.extmag1 then if args.extmag3 > args.extmag2 then magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag3 } else magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag2 } end else magazine = { args.extmag0, args.extmag1, args.extmag1, args.extmag1 } end else magazine = args.extmag0 end else magazine = math.huge end -- リロード時間 local reload if args.reloadratio2 > 0 and args.reloadratio2 < 1 then if args.reloadratio3 > 0 and args.reloadratio3 < args.reloadratio2 then if args.reloadratio1 > 0 and args.reloadratio1 < 1 and args.reloadratio1 > args.reloadratio2 then reload = { args.reload, args.reloadratio1 * args.reload, args.reloadratio2 * args.reload, args.reloadratio3 * args.reload } else reload = { args.reload, args.reload, args.reloadratio2 * args.reload, args.reloadratio3 * args.reload } end else local reload2 = args.reloadratio2 * args.reload reload = { args.reload, args.reload, reload2, reload2 } end else reload = args.reload end local ttkc = TTKCalculator.new(firerate, magazine, reload, { raise = args.raise, }) return ttkc end local function getContentLanguage(lang) local language = lang or mw.language.getContentLanguage().code return language == 'en' and 'en' or 'ja' end local function renderTable(args) local lang = getContentLanguage(args.lang) local res = mw.loadData('Module:DamageTable/configuration')[lang] local shieldinfo = args.shieldinfo or require('Module:Stat/Shield')[args.shieldpreset] local skullpiercer = args.skullpiercer or 1 local headMul = args.head or 2 local hideNoHelmets = shieldinfo.helmets.level0.disabled local minHead if hideNoHelmets then minHead = shieldinfo.helmets.level1.func(args.headmax) else minHead = args.headmax end local minCount, _ = getShotCount( minHead, 100, 0, { damage = math.max(args.damage, args.damagemax), beamdamage = math.max(args.beamdamage, args.beamdamagemax), ticks = args.ticks, mul = math.max(args.mul, args.mulmax), pellet = math.max(args.pellet, args.pelletmax), amped = true, charged = math.max(args.charged, args.chargedmax), disruptor = math.max(args.disruptor, args.disruptorsup), hammerpoint = math.max(args.hammerpoint, args.hammerpointsup), passthrough = 1, }) local damagemin = math.min(args.damage, args.damagemin) local mininfo = { damage = damagemin, beamdamage = math.min(args.beamdamage, args.beamdamagemin), ticks = args.ticks, mul = math.min(args.mul, args.mulmin), pellet = math.min(args.pellet, args.pelletmin), amped = false, charged = 1, disruptor = 1, hammerpoint = 1, passthrough = math.min(args.passthrough, args.passthroughsup), bleedthrough = shieldinfo.gunshieldBleedthrough, } local maxshield = shieldinfo.shields[#shieldinfo.shields] local legCount, _ = getShotCount(math.min(args.leg, args.legmin), maxshield.health, maxshield.shield, mininfo) local bodyWithGunSheild, _ = getShotCount(1, maxshield.health, maxshield.shield, mininfo, shieldinfo.gunshield) local maxCount = math.max(legCount, bodyWithGunSheild) local ttkCalculator = getTTKCalculator(args) local weaponinfo = { damage = args.damage, beamdamage = args.beamdamage, ticks = args.ticks, mul = args.mul, pellet = args.pellet, amped = args.amped, charged = args.charged, disruptor = args.disruptor, hammerpoint = args.hammerpoint, passthrough = args.passthrough, bleedthrough = shieldinfo.gunshieldBleedthrough, useRound = args.round, minCount = minCount, maxCount = maxCount, shields = shieldinfo.shields, ttkCalculator = ttkCalculator, } local colspan, info, level2first, level3first if skullpiercer > 1 then colspan = 3 info = { level1 = { { breaktop = false, breakbottom = false, colspan = 3 }, }, level1top = { { breaktop = true, breakbottom = true, colspan = 3 }, }, level1gunshiled = { { breaktop = false, breakbottom = true, colspan = 3 }, }, level2 = hideNoHelmets and { { breaktop = true, breakbottom = false, colspan = 2 }, } or { { breaktop = true, breakbottom = true }, { breaktop = true, breakbottom = false, colspan = 2 }, }, level2gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false, colspan = 2 }, }, level3 = hideNoHelmets and { { breaktop = false, breakbottom = true }, { breaktop = false, breakbottom = false }, } or { { breaktop = true, breakbottom = true }, { breaktop = false, breakbottom = true }, { breaktop = false, breakbottom = false }, }, level3first = { { breaktop = false, breakbottom = false, rowspan = 6, content = res.targets.head, verticalAlign = 'top' }, { breaktop = false, breakbottom = true }, { breaktop = false, breakbottom = false }, }, level3top = { { breaktop = false, breakbottom = true, colspan = 2 }, { breaktop = false, breakbottom = false }, }, } else colspan = 2 info = { level1 = { { breaktop = false, breakbottom = false, colspan = 2 }, }, level1gunshiled = { { breaktop = false, breakbottom = true, colspan = 2 }, }, level2 = hideNoHelmets and { { breaktop = false, breakbottom = false }, } or { { breaktop = true, breakbottom = true }, { breaktop = false, breakbottom = false }, }, level2first = { { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.head, verticalAlign = 'top' }, { breaktop = false, breakbottom = false }, }, level2gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false }, }, } info.level1top = info.level1gunshiled end if hideNoHelmets then if skullpiercer > 1 then level2first = info.level2 level3first = info.level3first else level2first = info.level2first end else level2first = info.level2 if skullpiercer > 1 then level3first = info.level3 end end local table = mw.html.create('table') :addClass('wikitable') :addClass('numbertable') :addClass('damagetable') if args.caption ~= nil then table:tag('caption') :wikitext(args.caption) end renderHeader(table, args.mul, colspan, shieldinfo.shields, res) -- Headshot damage if headMul > 1 then if not hideNoHelmets then if skullpiercer > 1 then renderRow( table, string.format(res.targets.skullpiercer0, args.skullpiercerrarity, skullpiercer), nil, skullpiercer, weaponinfo, info.level3top, res) end renderRow( table, string.format(res.targets.head_format, headMul), nil, headMul, weaponinfo, info.level1top, res) end if skullpiercer > 1 then local skullpiercerLv1Mul = shieldinfo.helmets.level1.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer1, args.skullpiercerrarity, skullpiercerLv1Mul), string.format(shieldinfo.helmets.level1.text, skullpiercer), skullpiercerLv1Mul, weaponinfo, level3first, res) end local hlmLv1Mul = shieldinfo.helmets.level1.func(headMul) renderRow( table, string.format(res.targets.helmet1, hlmLv1Mul), string.format(shieldinfo.helmets.level1.text, headMul), hlmLv1Mul, weaponinfo, level2first, res) if skullpiercer > 1 then local skullpiercerLv2Mul = shieldinfo.helmets.level2.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer2, args.skullpiercerrarity, skullpiercerLv2Mul), string.format(shieldinfo.helmets.level2.text, skullpiercer), skullpiercerLv2Mul, weaponinfo, info.level3, res) end local hlmLv2Mul = shieldinfo.helmets.level2.func(headMul) renderRow( table, string.format(res.targets.helmet2, hlmLv2Mul), string.format(shieldinfo.helmets.level2.text, headMul), hlmLv2Mul, weaponinfo, info.level2, res) if skullpiercer > 1 then local skullpiercerLv3Mul = shieldinfo.helmets.level3.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer3, args.skullpiercerrarity, skullpiercerLv3Mul), string.format(shieldinfo.helmets.level3.text, skullpiercer), skullpiercerLv3Mul, weaponinfo, info.level3, res) end local hlmLv3Mul = shieldinfo.helmets.level3.func(headMul) renderRow( table, string.format(res.targets.helmet3, hlmLv3Mul), string.format(shieldinfo.helmets.level3.text, headMul), hlmLv3Mul, weaponinfo, info.level2, res) end if args.leg == 1 then if args.mul < 1 or args.forcegunshield then renderRow(table, res.targets.bodylegs, nil, 1, weaponinfo, info.level1gunshiled, res) renderRow( table, res.targets.gunshield, shieldinfo.gunshieldLabel, 1, weaponinfo, info.level2gunshiled, res, shieldinfo.gunshield) else renderRow(table, res.targets.bodylegs, nil, 1, weaponinfo, info.level1, res) end else if shieldinfo.legAsBodyOnLowProfile and args.mul == 1.05 then renderRow(table, res.targets.bodylegs, nil, 1, weaponinfo, info.level1, res) else if args.mul < 1 or args.forcegunshield then renderRow(table, res.targets.body, nil, 1, weaponinfo, info.level1gunshiled, res) renderRow( table, res.targets.gunshield, shieldinfo.gunshieldLabel, 1, weaponinfo, info.level2gunshiled, res, shieldinfo.gunshield) else renderRow(table, res.targets.body, nil, 1, weaponinfo, info.level1, res) end renderRow(table, string.format(res.targets.legs, args.leg), nil, args.leg, weaponinfo, info.level1, res) end end return table end function p._main(args, frame) -- init value local initValues = { damage = 20, damagemin = 1000, damagemax = 0, beamdamage = 0, beamdamagemin = 0, beamdamagemax = 0, ticks = 0, pellet = 1, pelletmin = 0, pelletmax = 0, head = 2, headmax = -1, leg = 0.8, legmin = 0, mul = 1, mulmin = 0.85, mulmax = 1.05, charged = 1, chargedmax = 1, skullpiercer = 1, disruptor = 1, disruptorsup = 1, hammerpoint = 1, hammerpointsup = 1, passthrough = 1, passthroughsup = 1, rps = 0, rpsratio1 = 0, rpsratio2 = 0, rpsratio3 = 0, raise = 0, reload = 0, reloadratio1 = 0.963, reloadratio2 = 0.933, reloadratio3 = 0.9, extmag0 = 0, extmag1 = 0, extmag2 = 0, extmag3 = 0, } -- fix arguments for key, value in pairs(initValues) do args[key] = aw.getAsNumber(args[key], value) end if args.pelletmin == 0 then args.pelletmin = args.pellet end if args.pelletmax == 0 then args.pelletmax = args.pellet end if args.headmax == -1 then args.headmax = math.max(args.head, args.skullpiercer) end if args.legmin == 0 then args.legmin = args.leg end if args.beamdamagemin == 0 then args.beamdamagemin = args.beamdamage end if args.beamdamagemax == 0 then args.beamdamagemax = args.beamdamage end args.round = aw.getAsBoolean(args.round, false) args.amped = aw.getAsBoolean(args.amped, false) args.forcegunshield = aw.getAsBoolean(args.forcegunshield, false) args.rarity = args.rarity or 'epic' args.skullpiercerrarity = args.skullpiercerrarity or 'legendary' args.shieldpreset = args.shieldpreset or 'removelowprofile' return tostring(renderTable(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