• Welcome to the Kancolle Wiki!
  • If you have any questions regarding site content, account registration, etc., please visit the KanColle Wiki Discord

Difference between revisions of "Module:KanmusuModule"

From Kancolle Wiki
Jump to navigation Jump to search
Line 33: Line 33:
 
-- The ship infobox stuff...
 
-- The ship infobox stuff...
  
local function renderStats(ship, shipNum)
+
local function renderStats(ship)
 
   local shipName = ship.name[3]
 
   local shipName = ship.name[3]
 
   local CardImg = '<div class="top-image">[[File:Ship Card ' .. shipName .. ".png|218x300px|link=]]</div>"
 
   local CardImg = '<div class="top-image">[[File:Ship Card ' .. shipName .. ".png|218x300px|link=]]</div>"
Line 43: Line 43:
 
   local Banners =
 
   local Banners =
 
     '<td colspan="3" class="double-image" style="width:240px;height:60px">' .. BannerImg .. BannerDmgImg .. "</td>"
 
     '<td colspan="3" class="double-image" style="width:240px;height:60px">' .. BannerImg .. BannerDmgImg .. "</td>"
   local sortNo = ship.sortno or U.split(shipNum, "-")[1] or "?"
+
   local sortNo = ship.sortno or U.split(ship.no, "-")[1] or "?"
 
   local row1 = "<tr>" .. Cards .. '<th style="text-align: center;">' .. sortNo .. "</th>" .. Banners .. "</tr>"
 
   local row1 = "<tr>" .. Cards .. '<th style="text-align: center;">' .. sortNo .. "</th>" .. Banners .. "</tr>"
 
   -- Formatting Japanese
 
   -- Formatting Japanese
Line 88: Line 88:
 
   local JaName = ""
 
   local JaName = ""
 
   if
 
   if
     shipNum == "147" or shipNum == "311" or shipNum == "312" or shipNum == "313" or shipNum == "313a" or
+
     ship.no == "147" or ship.no == "311" or ship.no == "312" or ship.no == "313" or ship.no == "313a" or
       shipNum == "316"
+
       ship.no == "316"
 
   then --Russian ship markup
 
   then --Russian ship markup
 
     JaName =
 
     JaName =
Line 423: Line 423:
 
end
 
end
  
local ShipData = mw.loadData("Module:Data/Ship")
+
local ShipData = require("Module:Data/Ship")
local shipsByNo = mw.loadData("Module:Collection/ShipsByNo")
+
local shipsByNo = require("Module:Collection/ShipsByNo")
local shipsById = mw.loadData("Module:Collection/ShipsByApiId")
+
local shipsById = require("Module:Collection/ShipsByApiId")
  
 
local Ship = require("Module:Ship")
 
local Ship = require("Module:Ship")
  
local function loadShipData(ship)
+
local function loadShipData(no)
   local shipName = ship.name[3]
+
   local ship = Ship(shipsById[(U.find(shipsByNo, ShipData[no].name[3], "name") or {}).id] or "???")
  local shipKey = shipsById[(U.find(shipsByNo, shipName, "name") or {}).id] or "???"
+
   local data = {}
   local success, shipData = Ship(shipKey)
+
  data.no = no
   if not success then
+
  data.name = {ship:japanese_name() or "", ship:reading() or "", ship:name() or ""}
     return
+
  data.class = ship:class():name() or ""
 +
  data.type = ship:formatted_type() or ""
 +
  data.rarity = ship:rarity() or ""
 +
  data.hp = {ship:hp() or "", ship:hp_max() or ""}
 +
  data.fp = {ship:firepower() or "", ship:firepower_max() or ""}
 +
  data.armor = {ship:armor() or "", ship:armor_max() or ""}
 +
  data.torpedo = {ship:torpedo() or "", ship:torpedo_max() or ""}
 +
  data.evasion = {ship:evasion() or "", ship:evasion_max() or ""}
 +
  data.aa = {ship:aa() or "", ship:aa_max() or ""}
 +
  data.asw = {ship:asw() or "", ship:asw_max() or ""}
 +
  data.spd = ship:formatted_speed() or ""
 +
  data.los = {ship:los() or "", ship:los_max() or ""}
 +
  data.range = ship:formatted_range() or ""
 +
  data.luck = {ship:luck() or "", ship:luck_max() or ""}
 +
  data.aircraft = {}
 +
  data.equip = {}
 +
   for _, v in ipairs(ship._equipment) do
 +
     table.insert(data.equip, v.name or "")
 +
    table.insert(data.aircraft, v.size or "")
 
   end
 
   end
   ship.name = {shipData._japanese_name or "??", shipData._reading or "??", shipData:name() or "??"}
+
   data.artist = ship:artist() or ""
   -- ship.class = "Independence"
+
  data.seiyuu = ship:voice_actor() or ""
  -- ship.type = "Light Carrier"
+
   data.buildtime = {
  -- ship.rarity = 5
+
    ship._build_time or "",
  -- ship.hp = {31, 41}
+
    ship._buildable == true or false,
  -- ship.fp = {14, 32}
+
    ship._buildable_lsc == true or false
   -- ship.armor = {14, 30}
+
   }
   -- ship.torpedo = 0
+
   data.remodellv = ship:remodel_level() or ""
   -- ship.evasion = {22, 43}
+
   data.consumption = {ship:fuel() or "", ship:ammo() or ""}
   -- ship.aa = {32, 52}
+
   data.remodelreq = {ship._remodel_steel or 0, ship._remodel_ammo or 0}
   -- ship.aircraft = {23, 7, 2}
+
   data.dismantle = {
  -- ship.asw = {16, 52}
+
    ship._scrap_fuel or "",
  -- ship.spd = "Fast"
+
    ship._scrap_ammo or "",
  -- ship.los = {40, 68}
+
    ship._scrap_steel or "",
  -- ship.range = "Medium"
+
    ship._scrap_baux or ""
   -- ship.luck = {27, 87}
+
   }
  -- ship.equip = {"TBF", "SBD-5", ""}
+
  data.modernization = {
  -- ship.artist = ""
+
    ship._firepower_mod or "",
  -- ship.seiyuu = ""
+
    ship._torpedo_mod or "",
  -- ship.buildtime = {70, false, false}
+
    ship._aa_mod or "",
  -- ship.remodellv = ""
+
    ship._armor_mod or "",
  -- ship.consumption = {35, 40}
+
    ship._luck_mod or nil
  -- ship.remodelreq = ""
+
   }
   -- ship.dismantle = {3, 4, 14, 4}
+
   return data
   -- ship.modernization = {0, 0, 3, 2}
 
 
end
 
end
  
 
local function render(frame)
 
local function render(frame)
   local shipNum = frame.args[1]
+
   local ship = loadShipData(frame.args[1])
  local ship = ShipData[shipNum]
 
  -- loadShipData(ship)
 
 
   return '<div style="display:inline-block;vertical-align:top"><table style="{{border-radius|10px 10px 10px 10px}} border:1px solid #aaaaaa;min-width:495px"><tr><td>' ..
 
   return '<div style="display:inline-block;vertical-align:top"><table style="{{border-radius|10px 10px 10px 10px}} border:1px solid #aaaaaa;min-width:495px"><tr><td>' ..
     renderStats(ship, shipNum) ..
+
     renderStats(ship) ..
 
       "</td></tr><tr><td>" ..
 
       "</td></tr><tr><td>" ..
 
         renderEquipment(ship) ..
 
         renderEquipment(ship) ..
Line 476: Line 491:
 
end
 
end
  
return {KanmusuInfo = render}
+
local function test()
 +
  return render({args = {"525"}})
 +
end
 +
 
 +
-- print(p.test())
 +
 
 +
return {KanmusuInfo = render, test = test}

Revision as of 15:43, 10 September 2022

Documentation for this module may be created at Module:KanmusuModule/doc

local U = require("Module:Core")

-- Some formatting

local function formatBuildtime(minutes)
  return U.format {"${hours}:${minutes:2}", hours = math.floor(minutes / 60), minutes = minutes % 60}
end

local function formatTooltip(content, title)
  return tostring(mw.html.create("span"):attr("title", title):addClass("explain"):wikitext(content))
end

-- Some calculations

local function getTotalAircraft(ship)
  local total = 0
  if ship.aircraft ~= "" then
    for i, _ in pairs(ship.aircraft) do
      if ship.aircraft[i] == nil or ship.aircraft[i] == "" then
        total = total + 0
      else
        total = total + ship.aircraft[i]
      end
    end
  end
  return total
end

local function getMarriedHp(hp, maxHp)
  return math.min(maxHp, hp + ({4, 4, 4, 5, 6, 7, 7, 8, 8, 9})[math.floor(hp / 10) + 1])
end

-- The ship infobox stuff...

local function renderStats(ship)
  local shipName = ship.name[3]
  local CardImg = '<div class="top-image">[[File:Ship Card ' .. shipName .. ".png|218x300px|link=]]</div>"
  local CardDmgImg = '<div class="bottom-image">[[File:Ship Card ' .. shipName .. " Damaged.png|218x300px|link=]]</div>"
  local BannerImg = '<div class="top-image">[[File:Ship Banner ' .. shipName .. ".png|link=]]</div>"
  local BannerDmgImg = '<div class="bottom-image">[[File:Ship Banner ' .. shipName .. " Damaged.png|link=]]</div>"
  local Cards =
    '<td rowspan="10" class="double-image" style="width:218px;height:300px">' .. CardImg .. CardDmgImg .. "</td>"
  local Banners =
    '<td colspan="3" class="double-image" style="width:240px;height:60px">' .. BannerImg .. BannerDmgImg .. "</td>"
  local sortNo = ship.sortno or U.split(ship.no, "-")[1] or "?"
  local row1 = "<tr>" .. Cards .. '<th style="text-align: center;">' .. sortNo .. "</th>" .. Banners .. "</tr>"
  -- Formatting Japanese
  local kanji, form
  local formNum = mw.ustring.find(ship["name"][1], "[乙改甲航]")
  if formNum == nil then
    if mw.ustring.find(ship["name"][1], "%szwei") ~= nil then
      formNum = mw.ustring.find(ship["name"][1], "%szwei")
      kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
      form = "&#32;zwei"
    elseif mw.ustring.find(ship["name"][1], "%sdrei") ~= nil then
      formNum = mw.ustring.find(ship["name"][1], "%sdrei")
      kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
      form = "&#32;drei"
    elseif mw.ustring.find(ship["name"][1], "%sdue") ~= nil then
      formNum = mw.ustring.find(ship["name"][1], "%sdue")
      kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
      form = "&#32;due"
    elseif mw.ustring.find(ship["name"][1], "%sдва") ~= nil then
      formNum = mw.ustring.find(ship["name"][1], "%sдва")
      kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
      form = "&#32;два"
    elseif mw.ustring.find(ship["name"][1], "%sMk.II") ~= nil then
      if mw.ustring.find(ship["name"][1], "%sMk.II Mod.2") ~= nil then
        formNum = mw.ustring.find(ship["name"][1], "%sMk.II Mod.2")
        kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
        form = "&#32;Mk.II Mod.2"
      else
        formNum = mw.ustring.find(ship["name"][1], "%sMk.II")
        kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
        form = "&#32;Mk.II"
      end
    elseif mw.ustring.find(ship["name"][1], "%sреволюция") ~= nil then -- Gangut "Kai" exception
      kanji = mw.text.split(ship["name"][1], "%s")[1] .. "<br/>" .. mw.text.split(ship["name"][1], "%s")[2]
      form = ""
    else
      kanji = ship["name"][1]
      form = ""
    end
  else
    kanji = mw.ustring.sub(ship["name"][1], 1, formNum - 1)
    form = mw.ustring.sub(ship["name"][1], formNum, -1)
  end
  local JaName = ""
  if
    ship.no == "147" or ship.no == "311" or ship.no == "312" or ship.no == "313" or ship.no == "313a" or
      ship.no == "316"
   then --Russian ship markup
    JaName =
      '<ruby lang="ru"><rb>' ..
      kanji ..
        '<span lang="ru">' ..
          form .. "</span>" .. '</rb><rp> (</rp><rt lang="ja">' .. ship["name"][2] .. "</rt><rp>) </rp></ruby>"
  else
    if ship.name[2] then
      JaName =
        '<ruby lang="ja"><rb>' ..
        kanji .. "<span>" .. form .. "</span>" .. "</rb><rp> (</rp><rt>" .. ship.name[2] .. "</rt><rp>) </rp></ruby>"
    else
      JaName = '<ruby lang="ja"><rb>' .. kanji .. "<span>" .. form .. "</span>" .. "</rb></ruby>"
    end
  end
  -- Summary of basic ship info
  local isCVE =
    ship.type == "Light Carrier" and type(ship.asw) == "table" and type(ship.asw[1]) == "number" and ship.asw[1] > 0
  local shipType =
    isCVE and string.format('<span class="explain" title="CVE">%s[[Category:Escort Carriers]]</span>', ship.type) or
    ship.type
  local row2 = '<tr><th colspan="2">' .. JaName .. '</th><th colspan="2">' .. ship.name[3] .. "</th></tr>"
  local row3 = '<tr><td colspan="4" style="text-align: center;">' .. ship.class .. " Class " .. shipType .. "</td></tr>"
  local row4 =
    '<tr><td colspan="4"><hr style="border: 0; height: 1px; background-image: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));" /></td></tr>'
  -- Ship stats table
  local statLabel =
    '<th style="width: 65px; {{border-radius|12px 4px 4px 12px}} padding-left: 5px; padding-right: 5px; background-color: #eae1d1; color: #a3965c; text-align: right; vertical-align: baseline;">'
  local statBox =
    '<td style="{{border-radius|4px 12px 12px 4px}} padding-left: 5px; padding-right: 5px; border: 1px solid #a3965c; text-align: left; vertical-align: baseline;">'
  local hp = ship["hp"][1]
  local maxHp = ship["hp"][2]
  local HPinfo
  if maxHp then
    local marriedHp = getMarriedHp(hp, maxHp)
    local maxModHp = math.min(hp + 2, maxHp)
    local maxModMarriedHp = math.min(marriedHp + 2, maxHp)
    local hpSpan1 = hp == maxModHp and hp or formatTooltip(hp, string.format("%d with HP modernization", maxModHp))
    local hpSpan2 =
      formatTooltip(
      marriedHp,
      marriedHp == maxModMarriedHp and "Married" or string.format("Married, %d with HP modernization", maxModMarriedHp)
    )
    HPinfo = statLabel .. "HP [[File:IcoHP.png|HP]]</th>" .. statBox .. hpSpan1 .. "→" .. hpSpan2 .. "</td>"
  else
    HPinfo = statLabel .. "HP [[File:IcoHP.png|HP]]</th>" .. statBox .. hp .. "</td>"
  end
  local FPinfo =
    statLabel .. "FP [[File:IcoAtk.png|Firepower]]</th>" .. statBox .. ship["fp"][1] .. "→" .. ship["fp"][2] .. "</td>"
  local row5 = "<tr>" .. HPinfo .. FPinfo .. "</tr>"
  -- Armor & Torpedo
  local Armorinfo =
    statLabel ..
    "ARM [[File:IcoArmor.png|Armor]]</th>" .. statBox .. ship["armor"][1] .. "→" .. ship["armor"][2] .. "</td>"
  local Torpedoinfo = statLabel .. "TORP [[File:IcoTorpedo.png|Torpedo]]</th>" .. statBox
  if ship["torpedo"] == 0 then
    Torpedoinfo = Torpedoinfo .. ship["torpedo"]
  else
    Torpedoinfo = Torpedoinfo .. ship["torpedo"][1] .. "→" .. ship["torpedo"][2]
  end
  local row6 = "<tr>" .. Armorinfo .. Torpedoinfo .. "</tr>"
  -- Evasion & AA
  local Evasioninfo =
    statLabel ..
    "EVA [[File:IcoEvasion.png|Evasion]]</th>" .. statBox .. ship["evasion"][1] .. "→" .. ship["evasion"][2] .. "</td>"
  local AAinfo = statLabel .. "AA [[File:IcoAA.png|Anti-Air]]</th>" .. statBox
  if ship["aa"] == 0 then
    AAinfo = AAinfo .. ship["aa"]
  else
    AAinfo = AAinfo .. ship["aa"][1] .. "→" .. ship["aa"][2]
  end
  local row7 = "<tr>" .. Evasioninfo .. AAinfo .. "</tr>"
  -- Planes & ASW
  local aircraftTotal = getTotalAircraft(ship)
  local Planeinfo = statLabel .. "PLA [[File:IcoAircraft.png|Aircraft]]</th>" .. statBox .. aircraftTotal .. "</td>"
  local ASWinfo = statLabel .. "ASW [[File:IcoASW.png|Anti-Submarine Warfare]]</th>" .. statBox
  if ship["asw"] == 0 then
    ASWinfo = ASWinfo .. ship["asw"]
  else
    ASWinfo = ASWinfo .. ship["asw"][1] .. "→" .. ship["asw"][2]
  end
  local row8 = "<tr>" .. Planeinfo .. ASWinfo .. "</tr>"
  -- Speed & LOS
  local Speedinfo = statLabel .. "SPD [[File:IcoSpeed.png|Speed]]</th>" .. statBox .. ship["spd"] .. "</td>"
  local LOSinfo =
    statLabel ..
    "LOS [[File:IcoLOS.png|Line of Sight]]</th>" .. statBox .. ship["los"][1] .. "→" .. ship["los"][2] .. "</td>"
  local row9 = "<tr>" .. Speedinfo .. LOSinfo .. "</tr>"
  -- Range & Luck
  local Rangeinfo = statLabel .. "RGE [[File:IcoRange.png|Range]]</th>" .. statBox .. ship["range"] .. "</td>"
  local Luckinfo =
    statLabel .. "LUK [[File:IcoLuck.png|Luck]]</th>" .. statBox .. ship["luck"][1] .. "→" .. ship["luck"][2] .. "</td>"
  local row10 = "<tr>" .. Rangeinfo .. Luckinfo .. "</tr>"
  local StatTable =
    "<table>" .. row1 .. row2 .. row3 .. row4 .. row5 .. row6 .. row7 .. row8 .. row9 .. row10 .. "</table>"
  return StatTable
end

local function renderEquipment(ship)
  local equipHeader = ""
  local planeStyle = '<td style="width: 25%; white-space: nowrap; text-align: center; vertical-align: top;">'
  local equipStyle = ""
  if ship["aircraft"] ~= "" then
    local equipHeader1 =
      '<th style="width: 25%; white-space: nowrap; {{border-radius|12px 4px 4px 12px}} background-color: #efe6d7; color: #a3965c;">Aircraft</th>'
    local equipHeader2 =
      '<th style="width: 75%; white-space: nowrap; {{border-radius|4px 12px 12px 4px}} background-color: #efe6d7; color: #a3965c; vertical-align: baseline;">Equipment</th>'
    equipHeader = equipHeader1 .. equipHeader2
    equipStyle = '<td style="width: 75%; max-width: 375px; text-align: center; vertical-align: baseline;">'
  else
    equipHeader =
      '<th style="white-space: nowrap; {{border-radius|12px 12px 12px 12px}} background-color: #efe6d7; color: #a3965c; vertical-align: baseline;">Equipment</th>'
    equipStyle = '<td style="white-space: nowrap; text-align: center; vertical-align: baseline;">'
  end
  local numRows = math.max(4, U.isize(ship["equip"]))
  local equipTable = ""
  for i = 1, numRows, 1 do
    local equipRow = "<tr>"
    if ship["aircraft"] ~= "" then
      if ship["aircraft"][i] ~= nil then
        equipRow = equipRow .. planeStyle .. ship["aircraft"][i] .. "</td>" .. equipStyle
      else
        equipRow = equipRow .. planeStyle .. "</td>" .. equipStyle
      end
      if ship["equip"] ~= "" then
        if ship["equip"][i] == "" or ship["equip"][i] == "Unequipped" then
          equipRow = equipRow .. "-Unequipped-</td></tr>"
        elseif ship["equip"][i] == nil then
          equipRow = equipRow .. "''-Locked-''</td></tr>"
        else
          if string.find(ship["equip"][i], "%★") then
            local a, b = string.match(ship["equip"][i], "^(.+)★(.+)$")
            equipRow = equipRow .. "[[" .. a .. "|" .. a .. "★" .. b .. "]]</td></tr>"
          else
            equipRow = equipRow .. "[[" .. ship["equip"][i] .. "]]</td></tr>"
          end
        end
      else
        equipRow = equipRow .. "''-Locked-''</td></tr>"
      end
    else
      equipRow = equipRow .. equipStyle
      if ship["equip"] ~= "" then
        if ship["equip"][i] == "" or ship["equip"][i] == "Unequipped" then
          equipRow = equipRow .. "-Unequipped-</td></tr>"
        elseif ship["equip"][i] == nil then
          equipRow = equipRow .. "''Locked''</td></tr>"
        else
          if string.find(ship["equip"][i], "%★") then
            local a, b = string.match(ship["equip"][i], "^(.+)★(.+)$")
            equipRow = equipRow .. "[[" .. a .. "|" .. a .. "★" .. b .. "]]</td></tr>"
          else
            equipRow = equipRow .. "[[" .. ship["equip"][i] .. "]]</td></tr>"
          end
        end
      else
        equipRow = equipRow .. "''Locked''</td></tr>"
      end
    end
    equipTable = equipTable .. equipRow
  end
  return '<table style="width: 100%">' .. equipHeader .. equipTable .. "</table>"
end

local function renderModernization(ship)
  local RscHeader =
    '<th style="width: 25%; white-space: nowrap; {{border-radius|12px 4px 4px 12px}} background-color: #3baef5; color: #ffffff; padding-left: 5px; padding-right: 5px; text-align: right;">'
  local RscData = '<td style="width: 25%; white-space: nowrap; text-align: center;">'
  local RscData2 = '<td colspan="3" style="width: 75%; white-space: nowrap; text-align: center;">'
  -- Construction info
  local constrheader = ""
  local constrdata = ""
  if ship["remodellv"] ~= nil and ship["remodellv"] ~= "" then
    constrheader = "Remodel Level"
    constrdata = ship["remodellv"]
  else
    constrheader = '<span class="explain-dash" title="h:mm">Build Time</span>'
    constrdata =
      type(ship.buildtime) ~= "table" and "??" or
      string.format(
        "%s (%s)",
        formatBuildtime(ship.buildtime[1]),
        ship.buildtime[2] and ship.buildtime[3] and "Normal, LSC" or ship.buildtime[2] and "Normal" or
          ship.buildtime[3] and "LSC" or
          "Unbuildable"
      )
  end
  local remodelinfo = ""
  if ship.remodelreq and ship.remodelreq ~= "" then
    remodelinfo =
      string.format(
      "[[File:IcoSteel.png|18px|Steel]] %d [[File:IcoAmmo.png|18px|Ammo]] %d",
      ship.remodelreq[1],
      ship.remodelreq[2]
    )
    if ship.remodelbp then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format("[[File:Item Icon Remodel Blueprint.png|25px|Blueprint|link=Blueprints]] %d", ship.remodelbp)
    end
    if ship.remodelcatapult then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format(
            "[[File:Item Icon Prototype Flight Deck Catapult.png|25px|Prototype Flight Deck Catapult|link=Prototype Flight Deck Catapult]] %d",
            ship.remodelcatapult
          )
    end
    if ship.remodelar then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format("[[File:Item Icon Action Report.png|25px|Action Report|link=Action Report]] %d", ship.remodelar)
    end
    if ship.remodeldevmat or ship.remodelconmat or ship.remodelgunmat or ship.remodelairmat then
      remodelinfo = remodelinfo .. "<br>"
    end
    if ship.remodeldevmat then
      remodelinfo =
        remodelinfo .. " " .. string.format("[[File:IcoDevmat.png|18px|Development Material]] %d", ship.remodeldevmat)
    end
    if ship.remodelconmat then
      remodelinfo =
        remodelinfo .. " " .. string.format("[[File:IcoConmat.png|18px|Construction Material]] %d", ship.remodelconmat)
    end
    if ship.remodelgunmat then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format(
            "[[File:Item Icon New Model Gun Mount Improvement Material.png|18px|New Model Gun Mount Improvement Material|link=New Model Gun Development Material]] %d",
            ship.remodelgunmat
          )
    end
    if ship.remodelairmat then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format(
            "[[File:Item Icon New Model Aerial Armament Material.png|18px|New Model Aerial Armament Material|link=New Model Aviation Development Material]] %d",
            ship.remodelairmat
          )
    end
    if ship.remodelarmmat then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format(
            "[[File:Item Icon New Model Armament Material.png|18px|New Model Armament Material|link=New Model Armament Material]] %d",
            ship.remodelarmmat
          )
    end
    if ship.remodelboiler then
      remodelinfo =
        remodelinfo ..
        " " ..
          string.format(
            "[[File:Item Icon New Model High Temperature High Pressure Boiler.png|18px|New Model High Temperature High Pressure Boiler|link=New Model High Temperature High Pressure Boiler]] %d",
            ship.remodelboiler
          )
    end
  end
  -- Construction & Remodel
  local row11 = ""
  if constrheader == "Build Time" then
    row11 =
      "<tr>" .. RscHeader .. constrheader .. "</th>" .. RscData .. constrdata .. '</td><td colspan="2">&nbsp;</td></tr>'
  else
    row11 =
      "<tr>" ..
      RscHeader ..
        constrheader ..
          "</th>" ..
            RscData ..
              constrdata .. "</td>" .. RscHeader .. "Remodel Req</th>" .. RscData .. remodelinfo .. "</td></tr>"
  end
  -- Consumption
  local consfuel = "[[File:IcoFuel.png|18px|Fuel]] " .. ship["consumption"][1]
  local consammo = "[[File:IcoAmmo.png|18px|Ammo]] " .. ship["consumption"][2]
  local row12 = "<tr>" .. RscHeader .. "Consumption</th>" .. RscData .. consfuel .. " " .. consammo .. "</td>"
  -- Scrap Info
  local scrapfuel = "[[File:IcoFuel.png|18px|Fuel]] " .. ship["dismantle"][1]
  local scrapammo = "[[File:IcoAmmo.png|18px|Ammo]] " .. ship["dismantle"][2]
  local scrapsteel = "[[File:IcoSteel.png|18px|Steel]] " .. ship["dismantle"][3]
  local scrapbauxite = "[[File:IcoBauxite.png|18px|Bauxite]] " .. ship["dismantle"][4]
  local scrapinfo = scrapfuel .. " " .. scrapammo .. " " .. scrapsteel .. " " .. scrapbauxite
  local row12 = row12 .. RscHeader .. "Dismantle</th>" .. RscData .. scrapinfo .. "</td></tr>"
  -- Modernization
  local modFP = "[[File:IcoAtkRemodel.png|25px|Firepower]] " .. ship["modernization"][1]
  local modTorp = "[[File:IcoTorpedoRemodel.png|25px|Torpedo]] " .. ship["modernization"][2]
  local modAA = "[[File:IcoAARemodel.png|25px|Anti-Air]] " .. ship["modernization"][3]
  local modArmor = "[[File:IcoArmorRemodel.png|25px|Armor]] " .. ship["modernization"][4]
  local modLuck = ""
  if ship["modernization"][5] ~= nil and ship["modernization"][5] ~= "" then
    modLuck = "[[File:IcoLuckRemodel.png|25px|Luck]] " .. ship["modernization"][5]
  end
  local modInfo = modFP .. " " .. modTorp .. " " .. modAA .. " " .. modArmor
  if modLuck ~= "" then
    modInfo = modInfo .. " " .. modLuck
  end
  local row13 = "<tr>" .. RscHeader .. "Modernization</th>" .. RscData2 .. modInfo .. "</td></tr>"
  return row13 .. row11 .. row12
end

local function renderArtists(ship)
  local RscHeader =
    '<th style="width: 25%; white-space: nowrap; {{border-radius|12px 4px 4px 12px}} background-color: #3baef5; color: #ffffff; padding-left: 5px; padding-right: 5px; text-align: right;">'
  local RscData = '<td style="width: 25%; white-space: nowrap; text-align: center;">'
  local illustrator =
    ship["artist"] ~= "Unknown" and ship["artist"] ~= "" and
    ("[[:Category:" .. ship["artist"] .. "|" .. ship["artist"] .. "]]") or
    "Unknown"
  local voiceactor =
    ship["seiyuu"] ~= "Unknown" and ship["seiyuu"] ~= "" and
    ("[[:Category:" .. ship["seiyuu"] .. "|" .. ship["seiyuu"] .. "]]") or
    "Unknown"
  return RscHeader ..
    "Artist</th>" .. RscData .. illustrator .. "</td>" .. RscHeader .. "Seiyuu</th>" .. RscData .. voiceactor .. "</td>"
end

local function renderCategories(ship)
  local categories = "[[Category:Ships]][[Category:" .. ship["class"] .. " Class]][[Category:" .. ship["type"] .. "s]]"
  if ship["artist"] ~= "Unknown" and ship["artist"] ~= "" then
    categories = categories .. "[[Category:" .. ship["artist"] .. "]]"
  end
  if ship["seiyuu"] ~= "Unknown" and ship["seiyuu"] ~= "" then
    categories = categories .. "[[Category:" .. ship["seiyuu"] .. "]]"
  end
  return categories
end

local ShipData = require("Module:Data/Ship")
local shipsByNo = require("Module:Collection/ShipsByNo")
local shipsById = require("Module:Collection/ShipsByApiId")

local Ship = require("Module:Ship")

local function loadShipData(no)
  local ship = Ship(shipsById[(U.find(shipsByNo, ShipData[no].name[3], "name") or {}).id] or "???")
  local data = {}
  data.no = no
  data.name = {ship:japanese_name() or "", ship:reading() or "", ship:name() or ""}
  data.class = ship:class():name() or ""
  data.type = ship:formatted_type() or ""
  data.rarity = ship:rarity() or ""
  data.hp = {ship:hp() or "", ship:hp_max() or ""}
  data.fp = {ship:firepower() or "", ship:firepower_max() or ""}
  data.armor = {ship:armor() or "", ship:armor_max() or ""}
  data.torpedo = {ship:torpedo() or "", ship:torpedo_max() or ""}
  data.evasion = {ship:evasion() or "", ship:evasion_max() or ""}
  data.aa = {ship:aa() or "", ship:aa_max() or ""}
  data.asw = {ship:asw() or "", ship:asw_max() or ""}
  data.spd = ship:formatted_speed() or ""
  data.los = {ship:los() or "", ship:los_max() or ""}
  data.range = ship:formatted_range() or ""
  data.luck = {ship:luck() or "", ship:luck_max() or ""}
  data.aircraft = {}
  data.equip = {}
  for _, v in ipairs(ship._equipment) do
    table.insert(data.equip, v.name or "")
    table.insert(data.aircraft, v.size or "")
  end
  data.artist = ship:artist() or ""
  data.seiyuu = ship:voice_actor() or ""
  data.buildtime = {
    ship._build_time or "",
    ship._buildable == true or false,
    ship._buildable_lsc == true or false
  }
  data.remodellv = ship:remodel_level() or ""
  data.consumption = {ship:fuel() or "", ship:ammo() or ""}
  data.remodelreq = {ship._remodel_steel or 0, ship._remodel_ammo or 0}
  data.dismantle = {
    ship._scrap_fuel or "",
    ship._scrap_ammo or "",
    ship._scrap_steel or "",
    ship._scrap_baux or ""
  }
  data.modernization = {
    ship._firepower_mod or "",
    ship._torpedo_mod or "",
    ship._aa_mod or "",
    ship._armor_mod or "",
    ship._luck_mod or nil
  }
  return data
end

local function render(frame)
  local ship = loadShipData(frame.args[1])
  return '<div style="display:inline-block;vertical-align:top"><table style="{{border-radius|10px 10px 10px 10px}} border:1px solid #aaaaaa;min-width:495px"><tr><td>' ..
    renderStats(ship) ..
      "</td></tr><tr><td>" ..
        renderEquipment(ship) ..
          '<table style="width:100%">' ..
            renderModernization(ship) ..
              renderArtists(ship) .. "</table></td></tr></table></div>" .. renderCategories(ship)
end

local function test()
  return render({args = {"525"}})
end

-- print(p.test())

return {KanmusuInfo = render, test = test}