模块:Ship Specs

来自星际公民宇宙百科
跳转至: 导航搜索

此模块的文档可以在模块:Ship Specs/doc创建

local p = {}
local itemNames = {
	["name_format"] = "[[%s|%s]]",
	["manufacturer"] = "制造商",
	["focus"] = "定位",
	["description"] = "描述",
	["production_status"] = "生产状态",
	["length"] = "长",
	["beam"] = "宽",
	["height"] = "高",
	["mass"] = "空重",
	["cargo_capacity"] = "载货量",
	["max_crew"] = "船员上限",
	["max_power_plant_size"] = "能源装置尺寸上限",
	["max_shield_size"] = "护盾尺寸上限",
	["max_primary_thruster"] = "主推进器上限",
	["max_maneuvering_thruster"] = "机动推进器上限",
	["max_retro_thruster"] = "制动推进器上限",
	["type"] = "类型",
	["size_count"] = "尺寸/数量",
	["length_unit_format"] = "%d M",
	["mass_unit_format"] = "%d KG",
	["cargo_unit_format"] = "%d SCU",
	["crew_unit_format"] = "%d 人",
	["size_unit_format"] = "S%d",

	["factory_propulsion"] = "原厂推进设备",
	["propulsion_specs_format"] = "S%d x%d",
	["propulsion_factory_format"] = "%s(S%d) x%d",
	["propulsion:Primary"] = "主推进器",
	["propulsion:Maneuvering"] = "机动推进器",
	["propulsion:Retro"] = "制动推进器",

	["factory_ordnance"] = "原厂武器设备",
	["ordnance_class_format"] = "%s类武器",
	["ordnance_specs_format"] = "S%d x%d",
	["ordnance_factory_format"] = "%s(S%d) x%d",

	["factory_modular"] = "原厂模块设备",
	["modular_specs_format"] = "S%d x%d",
	["modular_factory_format"] = "%s(S%d) x%d",
	["modular:Shield"] = "护盾",
	["modular:Power Plant"] = "能源装置",
	["modular:Additional"] = "附加装备",

	["factory_avionics"] = "原厂航电设备",
	["avionics_specs_format"] = "S%d x%d",
	["avionics_factory_format"] = "%s(S%d) x%d",

	["official_page_format"] = "[%s %s - 官方页面]",
}

local optionsToken = "8wBrvOMe1bWj"

local function isEnabled( options , name )
	if (options ~= nil) and (name ~= nil) then
		local value = options[name]
		return value == true or value == "true" or value == 1
	end
end

local function pairsByKeys( t, f )
    local a = {}
    for n in pairs(t) do table.insert(a, n) end
    table.sort(a, f)
    local i = 0      -- iterator variable
    local iter = function()   -- iterator function
    	i = i + 1
    	if a[i] == nil then return nil
    	else return a[i], t[a[i]]
      	end
    end
    return iter
end


local function getPropulsionOrder( type )
	if type == "Primary" then
		return 1
	elseif type == "Maneuvering" then
		return 2
	elseif type == "Retro" then
		return 3
	else
		return math.huge
	end
end

local function propulsionOrderByType( p1, p2 )
	return getPropulsionOrder(p1) < getPropulsionOrder(p2)
end

local function createInternalLink( text )
	return "[[" .. text .. "]]"
end

local function defualtWhenNil( value, defaultValue )
	if value then
		return value
	else
		return defaultValue
	end
end

local function anyInTable( table )
	if table then
		for k,v in pairs(table) do
			return true
		end
	else
		return false
	end
end

local function countInTable( table, key, num)
	if table[key] then
		table[key] = table[key] + num
	else
		table[key] = num	
	end
end

local function ensureSubTable( table, key )
	local subTable
	if table[key] then
		subTable = table[key]
	else
		subTable = {}
		table[key] = subTable
	end
	return subTable
end

local function shipTableRows( shipSpecsList , options)
	local rows = {}
	for shipIndex, shipSpecs in ipairs(shipSpecsList) do
		--mw.log(string.format("shipIndex:%d", shipIndex))
		for shipSpecs_key, shipSpecs_value in pairs(shipSpecs) do
			--mw.log(string.format("shipSpecs_key:%s", shipSpecs_key))
			local row = ensureSubTable(rows, shipSpecs_key)
			if (shipSpecs_key == "propulsion") or (shipSpecs_key == "ordnance") or (shipSpecs_key == "modular") or (shipSpecs_key == "avionics") then
				for ss_p_item_name, ss_p_item in pairs(shipSpecs_value) do
					if ss_p_item then
						local ss_p_item_type
						if shipSpecs_key == "ordnance" then
							ss_p_item_type = ss_p_item["class"]
						else
							ss_p_item_type = ss_p_item["type"]
						end
						local ss_p_item_max_size = tonumber(ss_p_item["max_size"])
						local ss_p_item_count = tonumber(ss_p_item["count"])
						if not ss_p_item_count then
							ss_p_item_count = 1
						end
						if ss_p_item_type and ss_p_item_max_size and (ss_p_item_max_size > 0) and (ss_p_item_count > 0) then
							local row_p = ensureSubTable(row, ss_p_item_type)
							local row_p_ship = ensureSubTable(row_p, shipIndex)
							local row_p_ship_specs = ensureSubTable(row_p_ship, "specs")
							local row_p_ship_factory = ensureSubTable(row_p_ship, "factory")
							countInTable(row_p_ship_specs, ss_p_item_max_size, ss_p_item_count)

							local ss_p_item_components = ss_p_item["components"]
							if ss_p_item_components then
								for ss_p_item_component_index, ss_p_item_component in ipairs(ss_p_item_components) do
									table.insert(row_p_ship_factory, { ["name"] = ss_p_item_component.name, ["size"] = ss_p_item_component.size, ["count"] = ss_p_item_component.count})
								end
							end
						end
					end
				end
			else
				row[shipIndex] = shipSpecs_value
			end
		end
	end
	return rows
end

local function createShipTable(shipTableRows, shipCount, options)
	local table_col_num = (2 * shipCount) + 1
	local h_table = mw.html.create("table"):addClass("ship-specs-table")

	local nameRow = shipTableRows["name"]
	local nameEnRow = shipTableRows["name_en"]
	if nameRow then
		local h_tr = h_table:tag("tr"):addClass("sps-name")
		if shipCount > 1 then
			h_tr:tag("td")
		end
		for i=1, shipCount do
			local h_td
			if shipCount > 1 then
				h_td = h_tr:tag("td"):attr({ colspan="2" })
			else
				h_td = h_tr:tag("td"):attr({ colspan="3" })
			end
			local name = nameRow[i]
			local nameEn = nameEnRow[i]
			if name then
				h_td:wikitext(string.format(itemNames["name_format"], nameEn, name))
			end
		end
	end

	local imageRow = shipTableRows["image"]
	if imageRow then
		local h_tr = h_table:tag("tr"):addClass("sps-image")
		if shipCount > 1 then
			h_tr:tag("td")
		end
		for i=1, shipCount do
			local h_td
			if shipCount > 1 then
				h_td = h_tr:tag("td"):attr({ colspan="2" })
			else
				h_td = h_tr:tag("td"):attr({ colspan="3" })
			end
			local image = imageRow[i]
			if image then
				h_td:wikitext(image)
			end
		end
	end

	local manufacturerRow = shipTableRows["manufacturer"]
	if manufacturerRow then
		local h_tr = h_table:tag("tr"):addClass("sps-base")
		h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(itemNames["manufacturer"]))
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local manufacturer = manufacturerRow[i]
			if manufacturer then
				h_td:wikitext(createInternalLink(manufacturer))
			end
		end
	end

	local descriptionRow = shipTableRows["description"]
	if descriptionRow and isEnabled(options, "show-description") then
		local h_tr = h_table:tag("tr"):addClass("sps-base")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["description"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local description = descriptionRow[i]
			if description then
				h_td:wikitext(description)
			end
		end
	end

	local focusRow = shipTableRows["focus"]
	if focusRow then
		local h_tr = h_table:tag("tr"):addClass("sps-base")
		h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(itemNames["focus"]))
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local focus = focusRow[i]
			if focus then
				h_td:wikitext(focus)
			end
		end
	end

	local productionStatusRow = shipTableRows["production_status"]
	local productionNoteRow = shipTableRows["production_note"]
	if productionStatusRow then
		local h_tr = h_table:tag("tr"):addClass("sps-base")
		h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(itemNames["production_status"]))
		for i=1,shipCount do
			local productionStatus = productionStatusRow[i]
			local productionNote
			if productionNoteRow then
				productionNote = productionNoteRow[i]
			end
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			if productionStatus then
				h_td:wikitext(productionStatus)
				if productionNote then
					h_td:wikitext("<br />")
				end
			end
			if productionNote then
				h_td:wikitext(productionNote)
			end
		end
	end

	local lengthRow = shipTableRows["length"]
	if lengthRow then
		local h_tr = h_table:tag("tr"):addClass("sps-measurement")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["length"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local length = lengthRow[i]
			if length then
				h_td:wikitext(string.format(itemNames["length_unit_format"], length))
			end
		end
	end

	local beamRow = shipTableRows["beam"]
	if beamRow then
		local h_tr = h_table:tag("tr"):addClass("sps-measurement")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["beam"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local beam = beamRow[i]
			if beam then
				h_td:wikitext(string.format(itemNames["length_unit_format"], beam))
			end
		end
	end

	local heightRow = shipTableRows["height"]
	if heightRow then
		local h_tr = h_table:tag("tr"):addClass("sps-measurement")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["height"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local height = heightRow[i]
			if height then
				h_td:wikitext(string.format(itemNames["length_unit_format"], height))
			end
		end
	end

	local massRow = shipTableRows["mass"]
	if massRow then
		local h_tr = h_table:tag("tr"):addClass("sps-measurement")
		h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(itemNames["mass"]))
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local mass = massRow[i]
			if mass then
				h_td:wikitext(string.format(itemNames["mass_unit_format"], mass))
			end
		end
	end

	local cargo_capacity_row = shipTableRows["cargo_capacity"]
	if cargo_capacity_row then
		local h_tr = h_table:tag("tr"):addClass("sps-structural")
		h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(itemNames["cargo_capacity"]))
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local cargo_capacity = cargo_capacity_row[i]
			if cargo_capacity then
				h_td:wikitext(string.format(itemNames["cargo_unit_format"], cargo_capacity))
			end
		end
	end

	local max_crew_row = shipTableRows["max_crew"]
	if max_crew_row then
		local h_tr = h_table:tag("tr"):addClass("sps-structural")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["max_crew"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local max_crew = max_crew_row[i]
			if max_crew then
				h_td:wikitext(string.format(itemNames["crew_unit_format"], max_crew))
			end
		end
	end

	local max_power_plant_size_row = shipTableRows["max_power_plant_size"]
	if max_power_plant_size_row then
		local h_tr = h_table:tag("tr"):addClass("sps-structural")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["max_power_plant_size"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local max_power_plant_size = max_power_plant_size_row[i]
			if max_power_plant_size then
				h_td:wikitext(string.format(itemNames["size_unit_format"], max_power_plant_size))
			end
		end
	end

	local max_shield_size_row = shipTableRows["max_shield_size"]
	if max_shield_size_row then
		local h_tr = h_table:tag("tr"):addClass("sps-structural")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["max_shield_size"])
		for i=1,shipCount do
			local h_td = h_tr:tag("td"):addClass("sps-cell"):attr({ colspan="2" })
			local max_shield_size = max_shield_size_row[i]
			if max_shield_size then
				h_td:wikitext(string.format(itemNames["size_unit_format"], max_shield_size))
			end
		end
	end

	local propulsion_row = shipTableRows["propulsion"]
	if anyInTable(propulsion_row) then
		local h_tr = h_table:tag("tr"):addClass("sps-propulsion-title")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["type"])
		for shipIndex=1,shipCount do
			h_tr:tag("td"):addClass("sps-cell-h1"):wikitext(itemNames["size_count"])
			h_tr:tag("td"):addClass("sps-cell-h2"):wikitext(itemNames["factory_propulsion"])
		end
		for p_type, p_row in pairsByKeys(propulsion_row, propulsionOrderByType) do
			h_tr = h_table:tag("tr"):addClass("sps-propulsion")
			h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(defualtWhenNil(itemNames["propulsion:" .. p_type], p_type)))
			for shipIndex=1,shipCount do
				local h_td_specs = h_tr:tag("td"):addClass("sps-cell-h1")
				local h_td_factory = h_tr:tag("td"):addClass("sps-cell-h2")
				local p_row_ship = p_row[shipIndex]
				if p_row_ship then
					local p_row_ship_specs = p_row_ship["specs"]
					if p_row_ship_specs then
						for specs_size, specs_count in pairs(p_row_ship_specs) do
							h_td_specs:wikitext(string.format(itemNames["propulsion_specs_format"], specs_size, specs_count))
							h_td_specs:wikitext("<br />")
						end
					end
					local p_row_ship_factory = p_row_ship["factory"]
					if p_row_ship_factory then
						for factory_component_index, factory_component in ipairs(p_row_ship_factory) do
							h_td_factory:wikitext(string.format(itemNames["propulsion_factory_format"], factory_component.name, factory_component.size, factory_component.count))
							h_td_factory:wikitext("<br />")
						end
					end
				end
			end
		end
	end

	local ordnance_row = shipTableRows["ordnance"]
	if anyInTable(ordnance_row) then
		local h_tr = h_table:tag("tr"):addClass("sps-ordnance-title")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["type"])
		for shipIndex=1,shipCount do
			h_tr:tag("td"):addClass("sps-cell-h1"):wikitext(itemNames["size_count"])
			h_tr:tag("td"):addClass("sps-cell-h2"):wikitext(itemNames["factory_ordnance"])
		end
		for p_class, p_row in pairsByKeys(ordnance_row) do
			h_tr = h_table:tag("tr"):addClass("sps-ordnance")
			h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(string.format(itemNames["ordnance_class_format"], p_class)))
			for shipIndex=1,shipCount do
				local h_td_specs = h_tr:tag("td"):addClass("sps-cell-h1")
				local h_td_factory = h_tr:tag("td"):addClass("sps-cell-h2")
				local p_row_ship = p_row[shipIndex]
				if p_row_ship then
					local p_row_ship_specs = p_row_ship["specs"]
					if p_row_ship_specs then
						for specs_size, specs_count in pairs(p_row_ship_specs) do
							h_td_specs:wikitext(string.format(itemNames["ordnance_specs_format"], specs_size, specs_count))
							h_td_specs:wikitext("<br />")
						end
					end
					local p_row_ship_factory = p_row_ship["factory"]
					if p_row_ship_factory then
						for factory_component_index, factory_component in ipairs(p_row_ship_factory) do
							h_td_factory:wikitext(string.format(itemNames["ordnance_factory_format"], factory_component.name, factory_component.size, factory_component.count))
							h_td_factory:wikitext("<br />")
						end
					end
				end

			end
		end
	end

	local modular_row = shipTableRows["modular"]
	if anyInTable(modular_row) then
		local h_tr = h_table:tag("tr"):addClass("sps-modular-title")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["type"])
		for shipIndex=1,shipCount do
			h_tr:tag("td"):addClass("sps-cell-h1"):wikitext(itemNames["size_count"])
			h_tr:tag("td"):addClass("sps-cell-h2"):wikitext(itemNames["factory_modular"])
		end
		for p_type, p_row in pairs(modular_row) do
			h_tr = h_table:tag("tr"):addClass("sps-modular")
			h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(defualtWhenNil(itemNames["modular:" .. p_type], p_type)))
			for shipIndex=1,shipCount do
				local h_td_specs = h_tr:tag("td"):addClass("sps-cell-h1")
				local h_td_factory = h_tr:tag("td"):addClass("sps-cell-h2")
				local p_row_ship = p_row[shipIndex]
				if p_row_ship then
					local p_row_ship_specs = p_row_ship["specs"]
					if p_row_ship_specs then
						for specs_size, specs_count in pairs(p_row_ship_specs) do
							h_td_specs:wikitext(string.format(itemNames["modular_specs_format"], specs_size, specs_count))
							h_td_specs:wikitext("<br />")
						end
					end
					local p_row_ship_factory = p_row_ship["factory"]
					if p_row_ship_factory then
						for factory_component_index, factory_component in ipairs(p_row_ship_factory) do
							h_td_factory:wikitext(string.format(itemNames["modular_factory_format"], factory_component.name, factory_component.size, factory_component.count))
							h_td_factory:wikitext("<br />")
						end
					end
				end

			end
		end
	end

	local avionics_row = shipTableRows["avionics"]
	if anyInTable(avionics_row) then
		local h_tr = h_table:tag("tr"):addClass("sps-avionics-title")
		h_tr:tag("td"):addClass("sps-title"):wikitext(itemNames["type"])
		for shipIndex=1,shipCount do
			h_tr:tag("td"):addClass("sps-cell-h1"):wikitext(itemNames["size_count"])
			h_tr:tag("td"):addClass("sps-cell-h2"):wikitext(itemNames["factory_avionics"])
		end
		for p_type, p_row in pairs(avionics_row) do
			h_tr = h_table:tag("tr"):addClass("sps-avionics")
			h_tr:tag("td"):addClass("sps-title"):wikitext(createInternalLink(defualtWhenNil(itemNames["avionics:" .. p_type], p_type)))
			for shipIndex=1,shipCount do
				local h_td_specs = h_tr:tag("td"):addClass("sps-cell-h1")
				local h_td_factory = h_tr:tag("td"):addClass("sps-cell-h2")
				local p_row_ship = p_row[shipIndex]
				if p_row_ship then
					local p_row_ship_specs = p_row_ship["specs"]
					if p_row_ship_specs then
						for specs_size, specs_count in pairs(p_row_ship_specs) do
							h_td_specs:wikitext(string.format(itemNames["avionics_specs_format"], specs_size, specs_count))
							h_td_specs:wikitext("<br />")
						end
					end
					local p_row_ship_factory = p_row_ship["factory"]
					if p_row_ship_factory then
						for factory_component_index, factory_component in ipairs(p_row_ship_factory) do
							h_td_factory:wikitext(string.format(itemNames["avionics_factory_format"], factory_component.name, factory_component.size, factory_component.count))
							h_td_factory:wikitext("<br />")
						end
					end
				end
			end
		end
	end

	local urlRow = shipTableRows["url"]
	if urlRow then
		local h_tr = h_table:tag("tr"):addClass("sps-url")
		if shipCount > 1 then
			h_tr:tag("td")
		end
		for i=1, shipCount do
			local h_td
			if shipCount > 1 then
				h_td = h_tr:tag("td"):attr({ colspan="2" })
			else
				h_td = h_tr:tag("td"):attr({ colspan="3" })
			end
			local url = urlRow[i]
			if url then
				local name
				if nameEnRow and nameEnRow[i] then
					name = nameEnRow[i]
				elseif nameRow and nameRow[i] then
					name = nameRow[i]
				else
					name = "Unkonwn"
				end
				h_td:wikitext(string.format(itemNames["official_page_format"], url, name))
			end
		end
	end

	return tostring(h_table)
end

function p.shipTable( frame )
	local options = {}
	local specsList = {}
	for name, arg in pairs(frame.args) do
		local status, result = pcall(mw.text.jsonDecode, arg)
		if status and result then
			if result["id"] and result["name"] then --'{ "id":"1", "name":"Ship Name" }'
				table.insert(specsList, result)
			elseif result[optionsToken] then --'{ "optionsToken":"", "arg1":"abc", "arg2":"def" }'
				options = result
			else
				mw.log(string.format("frame.args[%s] is an unknown json object.", name))
			end
		else
			mw.log(string.format("frame.args[%s] is an unknown object.", name))
		end
	end
	local specsListCount = table.getn(specsList)
	if specsListCount > 0 then
		--mw.log(mw.logObject(specsList))
		local rows = shipTableRows(specsList, options)
		--mw.log(mw.logObject(rows))
		return createShipTable(rows, specsListCount, options)
	end
end

function p.options( frame )
	local options = {}
	local optionsArgs = {}
	for name, arg in pairs(frame.args) do
		table.insert(optionsArgs, arg)
	end
	for index = 1, table.getn(optionsArgs) do
		if (index % 2) == 0 then
			options[optionsArgs[index - 1]] = optionsArgs[index]
		end
	end
	options[optionsToken] = true
	return mw.text.jsonEncode(options)
end

return p