Dead by Daylight Wiki
Template-info Documentação
Flag Name Use Text Output
decom This Unlockable has been decommissioned and no longer exists in the game. #loadout DESATIVADO(A) (This Unlockable has been decommissioned and no longer exists in the game.)
deprecated This Unlockable no longer spawns in the Bloodweb, but stockpiles of it can still be used in Trials. #loadout NÃO MAIS OBTIDO NA TEIA DE SANGUE (This Unlockable no longer spawns in the Bloodweb, but stockpiles of it can still be used in Trials.)
mobile This Unlockable is only available in Dead by Daylight Mobile #loadout APENAS DISPONÍVEM EM DBD MOBILE (This Unlockable is only available in Dead by Daylight Mobile)
notAvailable This Unlockable no longer spawns in the Bloodweb and can no longer be used in Trials, being greyed-out in the inventory.
It may temporarily return during an Event.
#loadout NÃO MAIS DISPONÍVEL (This Unlockable no longer spawns in the Bloodweb and can no longer be used in Trials, being greyed-out in the inventory.
It may temporarily return during an Event.
)
retired Same as notAvailable, but specifically for Unlockables that will officially not return. #loadout APOSENTADO(A) (Same as notAvailable, but specifically for Unlockables that will officially not return.)
secret Only applies to Offerings: this Offering is secret and will not turn around and reveal its identity during the burning sequence. #loadout SECRETO(A) (Only applies to Offerings: this Offering is secret and will not turn around and reveal its identity during the burning sequence.)
unused This Unlockable is not used in the Game, but exists in code. #loadout NÃO UTILIZADO(A) (This Unlockable is not used in the Game, but exists in code.)

local p = {}
local utils = require("Module:Utils")
local data = mw.loadData("Module:Datatable" .. utils.lang())
local str = require("Module:Strings")
local various = require("Module:Various")
local frame = mw.getCurrentFrame()
--local data = require("Module:Datatable")

local loadoutData
local loadoutDescData
local loadoutTypeDisplay = cstr.empty
local loadoutType = cstr.empty
local loadoutLink = cstr.empty
local loadoutTable = {}
local loadoutDescTable = {}

p.loDescriptions = {
	decom = "This Unlockable has been decommissioned and no longer exists in the game.",
	deprecated = "This Unlockable no longer spawns in the Bloodweb, but stockpiles of it can still be used in Trials.",
	mobile = "This Unlockable is only available in ''Dead by Daylight Mobile''",
	notAvailable = "This Unlockable no longer spawns in the Bloodweb and can no longer be used in Trials, being greyed-out in the inventory." .. br .. "It may temporarily return during an Event.",
	retired = "Same as notAvailable, but specifically for Unlockables that will officially not return.",
	secret = "Only applies to Offerings: this Offering is secret and will not turn around and reveal its identity during the burning sequence.",
	unused = "This Unlockable is not used in the Game, but exists in code.",
	unknownDesc = "Unable to retrieve a description for this flag"
}
local loDescriptions = p.loDescriptions

p.strings = {
	ptbHeader = "Esta descrição é baseada nas mudanças apresentadas na próxima Atualização: #patch#",
	wipHeader = "This description is being worked on or will be changed soon in order to improve clarity.",
	
	loadoutNotFound = "Unable to retrieve the #loadout or unable to display it. You can add it at #loadoutLink. Otherwise " .. cstr.contact,
	loadoutDescNotFound = "Unable to retrieve the #loadout description or unable to display it. You can add it at #loadoutLink. Otherwise " .. cstr.contact,
	unitNotFound = "Unable to retrieve the measurement unit for the tiered Perk values. " .. cstr.contact,
	perkNotFound = "Unable to retrieve the Perk. " .. cstr.contact,

	
	decom =             tooltip(bclr(16, "#loadout DESATIVADO(A)"), p.loDescriptions.decom, true, true),
	deprecated =        tooltip(bclr(5, "#loadout NÃO MAIS OBTIDO NA TEIA DE SANGUE"), p.loDescriptions.deprecated, true, true),
	mobile =            tooltip(bclr(4, "#loadout APENAS DISPONÍVEM EM DBD MOBILE"), p.loDescriptions.mobile, true, true),
	notAvailable =      tooltip(bclr(8, "#loadout NÃO MAIS DISPONÍVEL"), p.loDescriptions.notAvailable, true, true),
	retired =           tooltip(bclr(13, "#loadout APOSENTADO(A)"), p.loDescriptions.retired, true, true),
	secret =            tooltip(bclr(6, "#loadout SECRETO(A)"), p.loDescriptions.secret, true, true),
	unused =            tooltip(bclr(16, "#loadout NÃO UTILIZADO(A)"), p.loDescriptions.unused, true, true),
	unknownDesc =       tooltip(bclr(16, "#loadout COM EFEITOS DESCONHECIDOS"), p.loDescriptions.unknownDesc, true, true),
	
	--General Strings
	andString = "e", --Loadoout Page
	
	--Loadoout Page
	page_is = "é um(a)",
	page_aUnique = bclr("orange", "Única"),
	page_aGeneral = b("Geral"),
	page_dbdMobile = '#' .. i(cstr.gameName) .. ' Mobile#',
	
	page_offering = "Oferenda",
	page_item = "Item",
	page_addon = "Complemento",
	page_perk = "Vantagem",
	page_skill = "Habilidade",
	
	page_belongingTo = "pertencente a",
	page_availableToAll = "disponível para todos",
	page_allPlayers = "todos os Jogadres",
	page_andShared = "e compartilhada",
	page_forItems = "para",
	
	page_killers = "Assassinos",
	page_survivors = "Sobreviventes",
	
	page_mobile = "#It is only available on Mobile#",
	page_secret = "#It is secret#",
	page_deprecated = "#It is no longer available in the Bloodweb#",
	page_notAvailable = "#It is no longer available#",
	page_retired = "#It has been retired#",
	--offeringHeaderTextOrder = "#1# #2#...",
	
	page_prestigeText1 = "para",
	page_prestigeText2 = "respectivamente para desbloquear",
	page_prestigeText3 = "de",
	page_prestigeText4 = "para todos os outros Personagens",
	page_tier = "Nível",
	page_perks = "Vantagens",
	page_uniquePerks = "Vantagens Únicas", --article on Perks Page
	page_prestige = "Prestige",

	--loadout table:
	icon = "Ícone",
	name = "Nome",
	desc = "Descrição",
	cost = "Custo",
	character = "Personagem",
	slot = "Espaço",
	all = "Todos", --used for general perks
	
	bloodpoints = "Pontos de Sangue",
	
--	statusEffect = "Status Effect",
--	statusEffects = "Status Effects"
}
local strings = p.strings
--singular forms / mapping table
-- [loadoutTypeDisplay_NameForTable] = SINGULAR_FORM
p.loadoutStrings = {
	items = "ITEM",
	offerings = "OFERENDA",
	addons = "COMPLEMENTO",
	perks = "VANTAGEM",
	powers = "PODER",
	skills = "HABILIDADE",
}
----------------------------------------------
if utils.lang() ~= cstr.empty and (counter or 0) < 1 then
	counter = (counter or 0) + 1
	strings = require("Module:Loadout" .. utils.lang()).strings
end

local function loadoutUpperString() return string.upper(loadoutTypeDisplay) end
local function loadoutCapitalised() return utils.capitalizeName(loadoutTypeDisplay) end

--Table used for mapping which string should use which style
p.loadoutStringMapper = {
	loadoutNotFound = loadoutCapitalised,
	loadoutDescNotFound = loadoutCapitalised,
	
	unknownDesc = loadoutUpperString,
	retired = loadoutUpperString,
	mobile = loadoutUpperString,
	deprecated = loadoutUpperString,
	notAvailable = loadoutUpperString,
	unused = loadoutUpperString,
	decom = loadoutUpperString,
	secret = loadoutUpperString,
}

--rarities can be found in Module:Various

--Function setting global setting which loadout type is current processed
local function setLoadoutTable(loType)
	loadoutTypeDisplay = p.loadoutStrings[loType] -- ADD-ON
	loadoutType = loType -- addons
	loadoutTypeLower = string.replace(string.sub(loType, 1, -2), '-', cstr.empty) -- addon
	loadoutData = mw.loadData("Module:Datatable/Loadout" .. utils.lang())
	loadoutLink = link("Module:Datatable/Loadout/Descriptions", "Datatable/Loadout")
	loadoutTable = loadoutData[string.replace(loType:lower(), '-', cstr.empty)]
end

--This cannot be called before setLoadoutTable() function
local function loadDescriptionModule()
	loadoutDescData = mw.loadData("Module:Datatable/Loadout/Descriptions" .. utils.lang())
	loadoutDescTable = loadoutDescData[loadoutTypeLower .. "Descriptions"]
end

function p.getLoString(index)
	index = utils.resolveParameter(index, 1, true) or (index and strings[index] and index) or "unknownDesc"
	return strings[index]
end

function p.getLoDescription(index)
	index = utils.resolveParameter(index, 1, true) or (index and strings[index] and index) or "unknownDesc"
	return loDescriptions[index]
end

-------------------------------------------------------------------------
--                               Add-ons                               --
-------------------------------------------------------------------------
function p.getAddonsCount(cat, charType)
	setLoadoutTable("addons")
	return various.getCountElementsByCategory(cat, loadoutTable, charType)
end
function p.getAddonByName(name, withDesc)
	setLoadoutTable("addons")
	return getLoadoutByName(name, withDesc)
end
function p.getAddonDescription(name) --used directly from wiki
	return p.getAddonByName(name, true).desc
end
function p.getAddonTable(name)
	local item = p.getAddonByName(name, true)
	local tabParams = initialiseLoadoutTableParameters(name, tabParams)
	return getLoadoutTable(item, tabParams)
end
function p.getAddonsTable(names, params)
	setLoadoutTable("addons")
	local tabParams = initialiseLoadoutTableParameters(names, params)
	local loadoutList = getLoadoutByNames(names, true)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getAddonsByCategory(cat, charType)
	setLoadoutTable("addons")
	local tabParams = initialiseLoadoutTableParameters(cat)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.resolveAddonPage(pageName, params)
	setLoadoutTable("addons")
	local tabParams = {displayHeader = true, displayCost = true, displayName = false}
	tabParams = initialiseLoadoutTableParameters(pageName, tabParams)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.getAddonsByOwner(name)
	setLoadoutTable("addons")
	local tabParams = {displayHeader = true, assembleImage = true, displayName = true}
	local loadoutList = getLoadoutByOwner(name)
	return getLoadoutCategoryTable(loadoutList, tabParams)
end
function p.getAddonsByRarities(rarities, params)
	setLoadoutTable("addons")
	local tabParams = initialiseLoadoutTableParameters(rarities, params)
	local loadoutList = getLoadoutByRarities(rarities)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getAddonRarity(name)
	setLoadoutTable("addons")
	local loadoutObj = getLoadoutByName(name, true)
	return loadoutObj and loadoutObj.rarity or 0
end
function p.getAddonsHistory(names, params)
	setLoadoutTable("addons")
	local tabParams = initialiseLoadoutTableParameters(names, params) --should not have much of effect
	local loadoutList = getLoadoutByNames(names)
	return getLoadoutHistory(loadoutList, tabParams)
end
-------------------------------------------------------------------------
--                             Add-ons END                             --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
--                                Items                                --
-------------------------------------------------------------------------
function p.getItemsCount(cat, charType)
	setLoadoutTable("items")
	return various.getCountElementsByCategory(cat, loadoutTable, charType)
end
function p.getItemByName(name, withDesc)
	setLoadoutTable("items")
	return getLoadoutByName(name, withDesc)
end

function p.getItemDescription(name) --used directly from wiki
	return p.getItemByName(name, true).desc
end
function p.getItemTable(name)
	local item = p.getItemByName(name, true)
	local tabParams = initialiseLoadoutTableParameters(name, tabParams)
	return getLoadoutTable(item, tabParams)
end
function p.getItemsTable(names, params)
	setLoadoutTable("items")
	local tabParams = initialiseLoadoutTableParameters(names, params)
	local loadoutList = getLoadoutByNames(names, true)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getItemsByCategory(cat, charType)
	setLoadoutTable("items")
	local tabParams = initialiseLoadoutTableParameters(cat, params)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.resolveItemPage(pageName, params)
	setLoadoutTable("items")
	local tabParams = {displayHeader = true, displayCost = true, displayName = false}
	tabParams = initialiseLoadoutTableParameters(pageName, tabParams)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.getItemsByOwner(name)
	setLoadoutTable("items")
	local tabParams = {displayHeader = true, assembleImage = true, displayName = true}
	local loadoutList = getLoadoutByOwner(name)
	return getLoadoutCategoryTable(loadoutList, tabParams)
end
function p.getItemsByRarities(rarities, params)
	setLoadoutTable("items")
	local tabParams = initialiseLoadoutTableParameters(rarities, params)
	local loadoutList = getLoadoutByRarities(rarities)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getItemsHistory(names, params)
	setLoadoutTable("items")
	local tabParams = initialiseLoadoutTableParameters(names, params) --should not have much of effect
	local loadoutList = getLoadoutByNames(names)
	return getLoadoutHistory(loadoutList, tabParams)
end
-------------------------------------------------------------------------
--                              Items END                              --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
--                              Offerings                              --
-------------------------------------------------------------------------
function p.getOfferingsCount(cat, charType)
	setLoadoutTable("offerings")
	return various.getCountElementsByCategory(cat, loadoutTable, charType)
end
function p.getOfferingByName(name, withDesc)
	setLoadoutTable("offerings")
	return getLoadoutByName(name, withDesc)
end
function p.getOfferingDescription(name) --used directly from wiki
	return p.getOfferingByName(name, true).desc
end
function p.getOfferingTable(name)
	local item = p.getOfferingByName(name, true)
	local tabParams = initialiseLoadoutTableParameters(name, tabParams)
	return getLoadoutTable(item, tabParams)
end
function p.getOfferingsTable(names, params)
	setLoadoutTable("offerings")
	local tabParams = initialiseLoadoutTableParameters(names, params)
	local loadoutList = getLoadoutByNames(names, true)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getOfferingsByCategory(cat, charType)
	setLoadoutTable("offerings")
	local tabParams = initialiseLoadoutTableParameters(cat)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getOfferingsByRarities(rarities, params)
	setLoadoutTable("offerings")
	local tabParams = initialiseLoadoutTableParameters(rarities, params)
	local loadoutList = getLoadoutByRarities(rarities)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.resolveOfferingPage(pageName)
	setLoadoutTable("offerings")
	local tabParams = {displayHeader = true, displayCost = true, displayName = false}
	tabParams = initialiseLoadoutTableParameters(pageName, tabParams)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.resolveOfferingPage2(pageName)
	setLoadoutTable("offerings")
	local tabParams = {displayHeader = true, displayCost = true, displayName = false}
	tabParams = initialiseLoadoutTableParameters(pageName, tabParams)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.resolveOfferingsByRealm(pageName)
	setLoadoutTable("offerings")
	local tabParams = initialiseLoadoutTableParameters(rarities, params)
	local loadoutList = getLoadoutByRealm(pageName, true)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getOfferingsHistory(names, params)
	setLoadoutTable("offerings")
	local tabParams = initialiseLoadoutTableParameters(names, params) --should not have much of effect
	local loadoutList = getLoadoutByNames(names)
	return getLoadoutHistory(loadoutList, tabParams)
end
-------------------------------------------------------------------------
--                            Offerings END                            --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
--                                Perks                                --
-------------------------------------------------------------------------
function p.getPerksCount(cat, charType)
	setLoadoutTable("perks")
	return various.getCountElementsByCategory(cat, loadoutTable, charType)
end
function p.getPerkByName(name, withDesc)
	setLoadoutTable("perks")
	return getLoadoutByName(name, withDesc)
end
function p.getPerkDescription(name) --used directly from wiki
	return p.getPerkByName(name, true).desc
end
function p.getPerkTable(name)
	local item = p.getPerkByName(name, true)
	return getLoadoutTable(item)
end
function p.getPerksTable(names, params)
	setLoadoutTable("perks")
	local tabParams = initialiseLoadoutTableParameters(names, params)
	local loadoutList = getLoadoutByNames(names)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getPerksByCategory(cat, charType)
	setLoadoutTable("perks")
	local tabParams = {assembleImage = false}
	tabParams = initialiseLoadoutTableParameters(cat, tabParams)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.resolvePerkPage(pageName, params)
	setLoadoutTable("perks")
	local tabParams = initialiseLoadoutTableParameters(names, params)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.getPerkPageTable(perkName)
	setLoadoutTable("perks")
	local loadoutObj = (type(perkName) == types.table and not perkName.args and perkName) or getLoadoutByName(perkName, true)
	return getPerkPageTable(loadoutObj)
end 
function p.getPerksByOwner(name, params)
	setLoadoutTable("perks")
	local tabParams = initialiseLoadoutTableParameters(name, params)
	local loadoutList = getLoadoutByOwner(name)
	return getLoadoutCategoryTable(loadoutList, tabParams)
end
function p.getCharPerksByDLC(charType, order, dlcName)
	setLoadoutTable("perks")
	dlcName = dlcName or utils.resolveParameter(charType, 3)
	order = order or tonumber(utils.resolveParameter(charType, 2, true)) or 1
	charType = utils.resolveParameter(charType, 1)
	local tabParams = initialiseLoadoutTableParameters(charType, params)
	local loadoutList = getCharLoadoutByDLC(charType, order, dlcName)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getPerksHistory(names, params)
	setLoadoutTable("perks")
	local tabParams = initialiseLoadoutTableParameters(names, params) --should not have much of effect
	local loadoutList = getLoadoutByNames(names)
	return getLoadoutHistory(loadoutList, tabParams)
end
-------------------------------------------------------------------------
--                              Perks END                              --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
--                               Powers                                --
-------------------------------------------------------------------------
function p.getPowerByName(name, withDesc)
	setLoadoutTable("powers")
	return getLoadoutByName(name, withDesc)
end
function p.getPowerDescription(name) --used directly from wiki
	return p.getPowerByName(name, true).desc
end
function p.getPowersByCategory(cat, charType)
	setLoadoutTable("powers")
	local tabParams = {assembleImage = false}
	tabParams = initialiseLoadoutTableParameters(cat, tabParams)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.getPowerByOwner(name, params)
	setLoadoutTable("powers")
	local tabParams = initialiseLoadoutTableParameters(name, params)
	local loadoutList = getLoadoutByOwner(name)
	return (loadoutList and p.getPowerDescription(loadoutList[1].name, params)) or false
end

-------------------------------------------------------------------------
--                             Powers END                              --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
--                               Skills                                --
-------------------------------------------------------------------------
function p.getSkillsCount(cat, charType)
	setLoadoutTable("skills")
	return various.getCountElementsByCategory(cat, loadoutTable, charType)
end
function p.getSkillByName(name, withDesc)
	setLoadoutTable("skills")
	return getLoadoutByName(name, withDesc)
end
function p.getSkillDescription(name)
	return p.getSkillByName(name, true).desc
end
function p.getSkillTable(name, params)
	local tabParams = {displayHeader = true, displayCost = false, displaySlot = true}
	tabParams = initialiseLoadoutTableParameters(name, tabParams)
	local item = p.getSkillByName(name, true)
	return getLoadoutTable(item, tabParams)
end

function p.getSkillsByCategory(cat, charType)
	setLoadoutTable("skills")
	local tabParams = {displaySlot = true}
	tabParams = initialiseLoadoutTableParameters(cat, tabParams)
	local loadoutList = getLoadoutByCategory(cat, charType)
	return loadoutList and getLoadoutCategoryTable(loadoutList, tabParams) or false
end
function p.resolveSkillPage(pageName, params)
	setLoadoutTable("skills")
	local tabParams = {displayHeader = true, displayName = false, displayCost = false, displaySlot = true}
	tabParams = initialiseLoadoutTableParameters(pageName, tabParams)
	local loadoutObj = getLoadoutByName(pageName, true)
	return resolveLoadoutPage(loadoutObj, tabParams)
end
function p.getSkillByOwner(name, params)
	setLoadoutTable("skills")
	local tabParams = initialiseLoadoutTableParameters(name, params)
	local loadoutList = getLoadoutByOwner(name)
	return (loadoutList and p.getPowerDescription(loadoutList[1].name, params)) or false
end
-------------------------------------------------------------------------
--                             Skills END                              --
-------------------------------------------------------------------------
--------------------------------------------------------------------------
--                             LUA OBJECTS                              --
--------------------------------------------------------------------------

function p.getPerkObjectsByOwner(name)
	setLoadoutTable("perks")
	return getLoadoutByOwner({args={name = name, disableRestrictions = true}})
end

--------------------------------------------------------------------------
--                           LUA OBJECTS END                            --
--------------------------------------------------------------------------

function initialiseLoadoutTableParameters(directParams, flagParams)
	local flags =
	{
		assembleImage = true,
		displayHeader = false,
		displayName = true,
		displayCost = false,
		displaySlot = false,
		displayPortrait = false,
	}
	for fName, flag in pairs(flagParams or {}) do
		flags[fName] = flag
	end
	for fName, flag in pairs(flags) do
		local directFlagParam = utils.bool(utils.resolveParameter(directParams, fName, true))
		if directFlagParam ~= nil then
			flags[fName] = directFlagParam --in order to rewrite the field that is looping thorugh it needs to be change via index
		end
	end
	return flags
end

--Returns whole object
--THIS FUNCTION MUST BE CALLED BY OTHER FUNCTION SETTING loadoutTable VARIABLE!
function getLoadoutByName(name, withDesc)
	withDesc = withDesc or utils.resolveParameter(name, 2, true)
	name = utils.resolveParameter(name)
	for _, loItem in ipairs(loadoutTable) do
		if loItem.name == name then
			if withDesc then
				loadDescriptionModule()
				local loadoutObj = table.copy(loItem)

				if loadoutDescTable[loadoutObj.name] then --there is ["Name"] index for the loadout
					loadoutObj.desc = loadoutDescTable[loadoutObj.name].desc
				elseif loadoutDescTable[loadoutObj.id] and loadoutDescTable[loadoutObj.id].id == loadoutObj.id then --index matches with loadout's id
					loadoutObj.desc = loadoutDescTable[loadoutObj.id].desc
				else
					for _, loadoutDesc in ipairs(loadoutDescTable) do
						if loadoutObj.id == loadoutDesc.id then
							loadoutObj.desc = loadoutDesc.desc
							break
						end
					end
				end
				if not loadoutObj.desc then
					loadoutObj.desc = strings.loadoutDescNotFound
					loadoutObj.descNotFound = true
				end
				
				postprocessDescription(loadoutObj)
				--replacing #loadout with according word and the word styling
				--loadoutObj.desc = string.replace(strings.unusedLoadout, "#loadout", p.loadoutStringMapper.unusedLoadout()) .. loadoutObj.desc
				return loadoutObj
			end
			
			return loItem
		end
	end
end

--used for specific list of loadout elements
--THIS FUNCTION MUST BE CALLED BY OTHER FUNCTION SETTING loadoutTable VARIABLE!
function getLoadoutByNames(names)
	names = utils.resolveParameter(names, 1)
	local searchedLoadout = various.getElementsByNames(names, loadoutTable)
	
	utils.sortCosmeticsByRarityAndName(searchedLoadout)
	return ((searchedLoadout and not table.empty(searchedLoadout)) and searchedLoadout) or false
end

--THIS FUNCTION MUST BE CALLED BY OTHER FUNCTION SETTING loadoutTable VARIABLE!
function getLoadoutByRarities(rarities)
	rarities = utils.resolveParameter(rarities, 1)
	local searchedLoadout = various.getElementsByRarities(rarities, loadoutTable)
	
	utils.sortItemsByName(searchedLoadout)
	return ((searchedLoadout and not table.empty(searchedLoadout)) and searchedLoadout) or false
end

function getLoadoutByRealm(realm)
	realm = utils.resolveParameter(realm, 1)
	local mapsLogic = require("Module:Maps")
	realmObj = mapsLogic.getRealmByName(realm)
	realmTag = string.replace(string.replace((realmObj.techName or realmObj.name), space, cstr.empty), "'", cstr.empty)
	searchedLoadout = {}
	
	for _, offering in ipairs(loadoutTable) do
		if utils.isTagPresent(offering, realmTag) then
			table.add(searchedLoadout, offering)
		end
	end
	
	utils.sortCosmeticsByRarityAndName(searchedLoadout)
	return ((searchedLoadout and not table.empty(searchedLoadout)) and searchedLoadout) or false
end

function getLoadoutDescription(loadout)
	return p["get" .. utils.FirstLetterUpper(loadoutTypeLower) .. "Description"](loadout.name) or strings.loadoutDescNotFound
end

function postprocessDescription(loadout)
	--can be thrownchanged to loop, with flags = {"deprecated", "mobile", "notAvailable", "retired"}
	if loadout.descNotFound or loadout.notFound then 
		loadout.desc = string.replace(loadout.desc, "#loadoutLink", loadoutLink)
		loadout.desc = string.replace(loadout.desc, "#loadout", p.loadoutStringMapper.loadoutDescNotFound())
	end
	if loadout.unknownDesc then loadout.desc = string.replace(strings.unknownDesc, "#loadout", p.loadoutStringMapper.unknownDesc()) .. dnl .. loadout.desc end
	if loadout.deprecated then loadout.desc = string.replace(strings.deprecated, "#loadout", p.loadoutStringMapper.deprecated()) .. dnl .. loadout.desc end --currently replace feature is not used in deprecated string
	if loadout.mobile then loadout.desc = string.replace(strings.mobile, "#loadout", p.loadoutStringMapper.mobile()) .. dnl .. loadout.desc end
	if loadout.notAvailable then loadout.desc = string.replace(strings.notAvailable, "#loadout", p.loadoutStringMapper.notAvailable()) .. dnl .. loadout.desc end
	if loadout.retired then loadout.desc = string.replace(strings.retired, "#loadout", p.loadoutStringMapper.retired()) .. dnl .. loadout.desc end
	if loadout.unused or loadout.unusedVisible then loadout.desc = string.replace(strings.unused, "#loadout", p.loadoutStringMapper.unused()) .. dnl .. loadout.desc end
	if loadout.decom then loadout.desc = string.replace(strings.decom, "#loadout", p.loadoutStringMapper.decom()) .. dnl .. loadout.desc end
	if loadout.secret then loadout.desc = string.replace(strings.secret, "#loadout", p.loadoutStringMapper.secret()) .. dnl .. loadout.desc end

	loadout = processTagsDescriptionAutomation(loadout)
	
	subNames(loadout)
	subValues(loadout)
	processElementValues(loadout)
	if loadout.wip then --wip override ptb, having bigger urgency
		wrapWipBox(loadout)
	else
		wrapPtb(loadout) --ptb should not appear if wip is true
	end
end

function processTagsDescriptionAutomation(loadout)
	if loadout.deprecated or loadout.notAvailable or (loadout.killer and type(loadout.killer) == types.number and loadout.killer > 0) then
		return loadout
	end
	
	if loadout.tags then
		for _, tag in ipairs(loadout.tags) do
			if table.contains(various.eventTypes, tag) then
				loadout.eventItem = true --not necesarry but for clarity why not
				loadout.eventType = tag
				break
			end
		end
	end
	
	if not loadout.eventItem then
		return loadout
	end

	local eventList = various.getLiveEventsList()
	for _, event in ipairs(eventList) do
		if event.type == "event" and event.tags and utils.isTagPresent(event, loadout.eventType) then
			return loadout
		end
	end
	
	if		loadoutType == "items" then 
		loadout.desc = string.replace(strings.deprecated, "#loadout", p.loadoutStringMapper.deprecated()) .. dnl .. loadout.desc
	elseif	loadoutType == "addons" or loadoutType == "offerings" then
		loadout.desc = string.replace(strings.notAvailable, "#loadout", p.loadoutStringMapper.notAvailable()) .. dnl .. loadout.desc
	end
		
	return loadout
end

--used on dedicated #loadout page
function getLoadoutTable(loadoutObj, tabParams)
	tabParams.displayCost = (loadoutType == "perks" and not table.contains({11, 12}, loadoutObj.rarity)) or (loadoutType ~= "perks" and tabParams.displayCost) --11 = Limited, 12 = Limited & Craftable
	--[[loadoutObj = utils.resolveParameter(loadoutObj)
	local craftable = table.contains({11, 12}, loadoutObj.rarity) --11 = Limited, 12 = Limited & Craftable
	local header = strings.icon .. dhl .. strings.desc .. ((not craftable and dhl .. strings.cost) or cstr.empty)
	local iconObj = utils.getIconObject(loadoutObj.name)
	local icon = utils.assembleImage(loadoutTypeLower, loadoutObj.name, nil, {rarity = loadoutObj.rarity or 0})
	local cost = various.getElementCost(loadoutObj)]]
	--((loadoutData.loadoutCosts[loadoutObj.rarity] and utils.formatNum(loadoutData.loadoutCosts[loadoutObj.rarity], 0)) or " -") .. '<p style="margin: 4px">' .. file(utils.getIcon(ils.bloodpoints), "56px") .. '</p>'
	
	--[[local content =
		thLine(nil, header) ..
		tLine(nil, icon, loadoutObj.desc) ..
		((not craftable and tl .. class("BG-All", "BPBG-All", "BPBG") .. tl .. utils.clr(utils.resolveTextColorByBackground(utils.clr("Bright Red")), cost) .. nl) or cstr.empty)
	local result = utils.wrapBasicTable(content, nil, nil, true)]]
	
	return getLoadoutCategoryTable({loadoutObj}, tabParams)
	--return result
end

function getPerkPageTable(perk)
	local perksModule = require("Module:Perks" .. utils.lang())
	if perk == nil then return strings.perkNotFound end
	perk.desc = perk.desc or p.getPerkDescription(perk.name)
	local bpClasses1 = 'BG-All PerkCostsBG'
	local bpClasses2 = 'borderless'
	local bpClasses3 = 'SquareBG-#-enh'
	local perkIconFilename = perksModule.getPerkIconFilenameByPerk(perk, cstr.gif, true)
	--if file exist then no link, otherwise make link for link to upload
	local perkIcon = utils.assembleImage("perk", perk.name)
	local bpIcon = file('IconHelp bloodpoints' .. dot .. cstr.png, '56px', 'link=' .. strings.bloodpoints)
	local firstLevel = 2 --based on indexes in perkBPCosts list
	local lastLevel = 4
	

	-------------------------------- PC --------------------------------
	local pcView = 
		'<div class="perkWrapper displayFlex">' .. nl .. --style = "display: none"
			'<div class = "perkTable divTable displayFlex flexColumn">' .. nl ..
				'<div class = "perkInfo displayFlex">' .. nl ..
					'<div class = "perkIcon displayFlex flexColumn flexGrow">' .. nl ..
						'<div class= "perkIconHeader divTableHeader">' .. strings.icon .. '</div>' .. nl ..
						'<div class = "perkIconImage displayFlex flexCenter divTableCell">' .. perkIcon .. '</div>' .. nl ..
					'</div>' .. nl ..
					'<div class = "perkCost displayFlex flexColumn">' .. nl ..
						'<div class= "perkCostHeader divTableHeader">' .. strings.cost .. '</div>' .. nl ..
						'<div class = "perkIconImage displayFlex">' .. nl
							for i = firstLevel, lastLevel, 1 do
								pcView = pcView ..
									div(utils.formatNum(perksModule.perkBPCosts[i], 0) .. br .. bpIcon, string.gsub("perkCost#", "#", i-1), "displayFlex", "flexColumn", "flexCenter", "BG-All", "PerkCostsBG", "borderless", string.gsub(bpClasses3, "#", i)) .. nl
									--tl .. class(bpClasses1, bpClasses2, string.gsub(bpClasses3, "#", i)) .. tl .. utils.formatNum(perksModule.perkBPCosts[i], 0) .. br .. bpIcon .. nl
							end
							pcView = pcView ..
						'</div>' .. nl ..
					'</div>' .. nl ..
				'</div>' .. nl ..
				'<div class = "perkDescHeader divTableHeader">Description</div>' .. nl ..
				'<div class = "perkDesc divTableCell">' .. perk.desc .. '</div>' .. nl ..
			'</div>' .. nl ..
		'</div>' .. nl

	
	-------------------------------- Mobile --------------------------------
	--temporarily disabled
	local mobileView = cstr.empty
	--[[
		hl .. 'width = "128px"' .. tl .. strings.icon .. nl ..
		hl .. colspan(1) .. tl .. strings.cost .. nl .. ntl .. nl ..
		tl .. rowspan(3) .. tl .. center(perkIcon) .. nl
	for i = firstLevel, lastLevel, 1 do
		mobileView = mobileView ..
			tl .. center(bclr(i, utils.formatNum(perksModule.perkBPCosts[i], 0)) .. utils.IconLink(ils.bloodpoints, 'img')) .. nl .. ntl .. nl
	end
	mobileView = mobileView ..
		hl .. colspan(2) .. tl .. strings.desc .. nl .. ntl .. nl ..
		tl .. colspan(2) .. tl .. perk.desc .. nl
		
	mobileView = utils.wrapBasicTable(mobileView, 'mobileView')
	]]
	
	local result = pcView .. dnl .. mobileView
	
	--mw.log(result)
	return result
end

function resolvePerkPrestige(perk)
	if not perk then return strings.perkNotFound .. space .. brackets(strings.name .. colon .. space .. quotes(perk.name or cstr.empty)) end
	
	if not perk.character then
		return cstr.empty
	end
	
	local owner = getLoadoutOwner(perk)
	local isKiller = utils.isKiller(owner)
	
	return link(strings.page_perks .. '#' .. strings.page_uniquePerks, strings.page_prestige) .. space .. ((isKiller and the(owner)) or cstr.empty) .. ((not isKiller and owner.shortName) or owner.name) .. space .. strings.page_prestigeText1 .. space .. b(strings.page_prestige .. " 1, 2, 3") .. space .. 
		strings.page_prestigeText2 .. space .. b(clr(2, strings.page_tier .. space .. 'I') .. comma .. clr(3, strings.page_tier .. space .. 'II') .. comma .. clr(4, strings.page_tier .. space .. 'III')) .. space .. 
		strings.page_prestigeText3 .. space .. b(perk.name) .. space .. strings.page_prestigeText4 .. dot
	-- [[Perks#Unique Perks|Prestige]] the associated Character to '''Prestige 1, 2, 3''' respectively to unlock '''{{clr|2|Tier I}}, {{clr|3|Tier II}}, {{clr|4|Tier III}}''' of '''{{PAGENAME}}''' for all other Characters.
end

--THIS FUNCTION MUST BE CALLED BY OTHER FUNCTION SETTING loadoutTable VARIABLE!
function getLoadoutByCategory(cat, charType)
	charType = charType or utils.resolveParameter(cat, 2, true)
	cat = utils.resolveParameter(cat, 1)
	local searchedLoadout = various.getElementsByCategory(cat, loadoutTable, charType)
	
	utils.sortCosmeticsByRarityAndName(searchedLoadout)
	return ((searchedLoadout and not table.empty(searchedLoadout)) and searchedLoadout) or false
end

--THIS FUNCTION MUST BE CALLED BY OTHER FUNCTION SETTING loadoutTable VARIABLE!
function getLoadoutByOwner(params)
	local itemsCategoryParam = tonumber(utils.resolveParameter(params, "itemsCategory", true)) or utils.resolveParameter(params, "itemsCategory")
	local killerParam = tonumber(utils.resolveParameter(params, "killer", true)) or utils.resolveParameter(params, "killer")
	local categoryParam = tonumber(utils.resolveParameter(params, "category", true)) or utils.resolveParameter(params, "category")
	local decomParam = utils.bool(utils.resolveParameter(params, "decom", true))
	local unusedParam = utils.bool(utils.resolveParameter(params, "unused", true))
	local disableRestrictions = utils.bool(utils.resolveParameter(params, "disableRestrictions", true))

	local searchedLoadout = {}
	local category, itemsCategory
	
	local killersLogic = require("Module:Killers" .. utils.lang())
	local killer = (tonumber(killerParam) and killersLogic.getKillerById(killerParam) or tonumber(killerParam)) or killersLogic.getKillerByName(killerParam)

	local character = various.getCharacterByName(utils.resolveParameter(params, "name", true) or utils.resolveParameter(params, 1, true) or (type(params) == types.string and params) or utils.getPageTitle())

	for i, cat in pairs(loadoutData.categories or {}) do
		if itemsCategoryParam == cat then
			itemsCategory = i
			break
		end
		if categoryParam == cat then
			category = i
			break
		end
	end

	for i, loadout in ipairs(loadoutTable) do
		if	(	(loadout.itemsCategory == itemsCategoryParam or (itemsCategory and loadout.itemsCategory == itemsCategory)) 
			or	(type(killer) == types.table and (loadout.killer == killer.id or (type(loadout.killer) == types.table and table.contains(loadout.killer, killer.id))) or (type(killer) == types.number and loadout.killer == killer))
			or	(loadout.character and character and loadout.character == character.id and ((character.isKiller and loadout.charType == 'K') or (not character.isKiller and loadout.charType == 'S')))
			or	(loadout.category == categoryParam or (category and loadout.category == category))
			)
			and
			(
				(
					((decomParam and loadout.decom) or (not decomParam and not loadout.decom))
				and ((unusedParam and loadout.unused) or (not unusedParam and not loadout.unused)) 
				)
				or disableRestrictions
			)
				then
			
			table.add(searchedLoadout, loadout)
		end
	end

	utils.sortCosmeticsByRarityAndName(searchedLoadout)
	return ((searchedLoadout and not table.empty(searchedLoadout)) and searchedLoadout) or false
end

function getLoadoutCategoryTable(catTable, tabParams)
	local various = require("Module:Various")
	local result = cstr.empty
	if catTable and not table.empty(catTable) then
		for _, l in ipairs(catTable) do
			local loadout = table.copy(l)
			loadout.character = getLoadoutOwner(loadout)
			result = result ..
				ntl .. ((loadout.decom and class("decom", "decom-" .. loadoutTypeLower)) or ((loadout.unused or loadout.unusedVisible) and class("unused", "unused-" .. loadoutTypeLower)) or cstr.empty) .. nl ..
				hl .. ((tabParams.assembleImage and (utils.assembleImage(loadoutTypeLower, loadout.name, nil, {rarity = loadout.rarity or 1}))) or file(utils.getIcon(loadout.name), loadout.name, "96px")) .. nl ..
				((tabParams.displayName and hl .. link(loadout.name, loadout.displayName) .. nl) or cstr.empty) .. --if tabParams.displayName == nill then it will behave as no parameter was passed
				tl .. getLoadoutDescription(loadout) .. nl .. --this should be optimised as this cause searching through the offering table twice (first is the off object here and second search is inside getOfferingDescription function)
				((tabParams.displayCost and tl .. class("BG-All", "BPBG-All", "BPBG") .. tl .. utils.clr(utils.resolveTextColorByBackground(utils.clr("Bright Red")), various.getElementCost(loadout)) .. nl) or cstr.empty) ..
				((tabParams.displaySlot and loadout.slot and hl .. loadout.slot .. nl) or cstr.empty) ..
				((tabParams.displayPortrait and 
					hl .. ((loadout.character and ( link(loadout.character.name, various.getCharacterFirstName(loadout.character)) .. br .. 
					various.getCharPortrait(loadout.character, 150, false)
					)) or span(dot, 'display-none') .. strings.all) .. nl) or cstr.empty)
		end
		if tabParams.displayHeader then
			result = ntl .. nl .. 
			hl .. strings.icon .. 
			((tabParams.displayName and dhl .. strings.name) or cstr.empty) .. 
			dhl .. strings.desc .. 
			((tabParams.displayCost and dhl .. strings.cost) or cstr.empty) ..
			((tabParams.displaySlot and dhl .. strings.slot) or cstr.empty) ..
			((tabParams.displayPortrait and dhl .. strings.character) or cstr.empty) ..
				nl .. result
		end
		return utils.wrapBasicTable(result, (tabParams.displayPortrait and "sortable") or nil, nil, true)
	else
		result = {notFound = true, desc = strings.loadoutNotFound}
		postprocessDescription(result)
		return utils.wrapBasicTable(tl .. result.desc .. nl, nil, nil, true)
	end
	
end

function getPortraitOfLoadoutOwner(loadoutObj)
	return loadoutObj.charType .. string.format("%02d", loadoutObj.character and loadoutObj.character.id or getLoadoutOwner(loadoutObj).id) .. '_charSelect_portrait.png'
end

function resolveLoadoutPage(loadoutObj, tabParams)
	local result = cstr.empty
	
	if loadoutObj then
		various = require("Module:Various")
		local isSecret = p.isLoadoutSecret(loadoutObj)
		local offCharType = various.getCharTypeWord(loadoutObj, true)
		local rarity = false
		local rarityClr = false 
		local rarityName = cstr.empty
		
		if loadoutObj.rarity and various.rarity[loadoutObj.rarity] then
			rarity = various.rarity[loadoutObj.rarity]
			rarityClr = (rarity.clr == nil and loadoutObj.rarity) or rarity.clr or false
			rarityName = rarity.name or cstr.empty
		end
		result = result .. 
			utils.getDynamicString(
				{
					(loadoutObj.multiName and b(loadoutObj.displayName or loadoutObj.name) or link(loadoutObj.displayName or loadoutObj.name)) .. space .. strings.page_is .. space .. 
						((loadoutType == "perks" and (((loadoutObj.character and strings.page_aUnique) or (loadoutObj.charType and strings.page_aGeneral)) .. space)) or cstr.empty) ..
						
					((loadoutObj.rarity and various.rarity[loadoutObj.rarity] and article(rarity, true) .. (rarityClr and bclr(rarityClr, rarityName) or b(rarityName)) .. space) or (loadoutType ~= "perks" and article(loadoutTypeLower, true)) or cstr.empty) .. 
					skip(utils.IconLink(strings["page_" .. loadoutTypeLower])) .. 
					
					((table.contains({"offerings", "skills"}, loadoutType) and space ..  
						((loadoutObj.character and getUniqueOwnerString(loadoutObj)) or 
						 strings.page_belongingTo .. space .. ((offCharType and skip(utils.IconLink(offCharType))) or strings.page_allPlayers))) or cstr.empty) ..
					((loadoutType == "addons" and space .. getAddonOwnerString(loadoutObj)) or cstr.empty) ..
					((loadoutType == "perks" and space .. getUniqueOwnerString(loadoutObj)) or cstr.empty) ..
					dot,
					
					((isSecret and strings.page_secret .. dot) or cstr.empty),
					((loadoutObj.deprecated and strings.page_deprecated .. dot) or cstr.empty),
					((loadoutObj.notAvailable and strings.page_notAvailable .. dot) or cstr.empty),
					((loadoutObj.retired and strings.page_retired .. dot) or cstr.empty),
					((loadoutObj.mobile and strings.page_mobile .. dot) or cstr.empty)
				},
				strings[loadoutType .. "HeaderTextOrder"]
				) ..
			((loadoutType == "perks" and br .. resolvePerkPrestige(loadoutObj)) or cstr.empty) .. dnl ..
			((loadoutType == "perks" and getPerkPageTable(loadoutObj)) or getLoadoutTable(loadoutObj, tabParams))
	end
	
	return result
end

function getAddonOwnerString(loadoutObj)
	local result = 
		(loadoutObj.killer and getPowerString(loadoutObj)) or --addons for Killer's power
		(loadoutObj.itemsCategory and strings.page_forItems .. space .. utils.IconLink(loadoutData.categories[loadoutObj.itemsCategory])) --Survivor addons for items
		or nil
	return (result and space .. result) or cstr.empty
end

function getUniqueOwnerString(loadoutObj)
	if not loadoutObj then return strings.perkNotFound .. space .. brackets(strings.name .. colon .. space .. quotes(loadoutObj.name or cstr.empty)) end
	
	if not loadoutObj.character then
		return strings.page_availableToAll .. space .. utils.IconLink(((loadoutObj.charType == 'S' and strings.page_survivors) or strings.page_killers))
	end
	
	local owner = getLoadoutOwner(loadoutObj)
	local isKiller = utils.isKiller(owner)
	
	return 
		strings.page_belongingTo .. space ..
		utils.IconLink(
			utils.resolveCharacterIconLinkName(owner), 
			((isKiller and the(owner)) or cstr.empty) .. ((not isKiller and owner.shortName) or owner.name)
		)
end

function getLoadoutOwner(loadoutObj)
	return utils.getCharacter(loadoutObj)
end

--[order] - #th character from DLC
function getCharLoadoutByDLC(charType, index, dlcName)
	local dlcsLogic = require("Module:DLCs" .. utils.lang())
	dlcName = dlcsLogic.getShortName(dlcName)
	local dlc = dlcsLogic.getDlcByName(dlcName)
	local characters = various.getCharsByDlc(dlc, charType) --various.getCharsByDlc(dlc, charType)

	if #characters > 0 then
		return getLoadoutByOwner((characters[index] or characters[1]).name)
	end
end

function getPowerString(loadoutObj)
	local killersLogic = require("Module:Killers" .. utils.lang())
	local result = strings.page_forItems .. space
	local killerPowerList = {}
	
	if loadoutObj.killer then
		if type(loadoutObj.killer) == types.table and table.count(loadoutObj.killer) > 1 then
			result = space .. strings.page_andShared .. space
		else
			if loadoutObj.killer == 0 then 
				return strings.page_availableToAll .. space .. utils.IconLink(strings.page_killers)
			end
			loadoutObj.killer = {loadoutObj.killer}
		end
		
		for i, killerId in ipairs(loadoutObj.killer) do
			local pwr = killersLogic.getKillerPower(killersLogic.getKillerById(killerId))
			if pwr then
				table.add(killerPowerList, pwr)
			end
		end
	end
	
	result = result .. table.join(table.get(killerPowerList, "name"), {comma, ((#killerPowerList > 2 and comma) or cstr.empty) .. space .. strings.andString .. space}, {"iconLink"})
	return result
end

function p.isLoadoutSecret(loadout)
	return utils.isTagPresent(loadout, "Secret")
end

function getLoadoutHistory(loadoutList, tabParams)
	local historyData = mw.loadData("Module:Datatable/Loadout/History")
	local result = cstr.empty
	
	for _, l in ipairs(loadoutList) do
		local loadout = table.copy(l)
		local tabberTable = {}
		loadout.history = historyData[loadoutTypeLower .. "DescriptionsHistory"][loadout.name]
		if loadout.history then
			for _, historyRecordObj in ipairs(loadout.history) do
				local historyRecord = table.copy(historyRecordObj)
				local tabber = {}
				local iconObj = utils.getIconObject(historyRecord.icon or loadout.name)
				local icon = cstr.empty
				if iconObj.assembly then
					icon = utils.assembleImage(loadoutTypeLower, loadout.name, 96, {rarity = historyRecord.rarity or 1})
				else
					icon = file(utils.getIcon(historyRecord.icon or loadout.name), "96px")
				end
				historyRecord.name = loadout.name
				
				postprocessDescription(historyRecord)
				
				tabber.header = historyRecord.displayVersion or historyRecord.version
				tabber.content = 
					utils.wrapBasicTable(
						hl .. strings.icon .. dhl .. strings.desc .. nl .. ntl .. nl ..
						tl .. icon .. dtl .. historyRecord.desc .. nl
					,nil, nil, false)
				
				table.add(tabberTable, tabber)
			end
			result = result .. utils.getTabberFromTable(tabberTable) .. nl
		end
	end
	return result
end

--------------------------------------------------------------------------------
function wrapPtb(loadout)
	if loadout.desc ~= nil then
		local processedString = processString(strings.ptbHeader, loadout)
		loadout.desc = ptb(loadout.desc, processedString, loadout.patch)
	end
	return loadout
end

local function wrapWipBox(loadout)
	if loadout.desc ~= nil then
		local wipHeader = processString(strings.wipHeader, loadout)
		loadout.desc = utils.wipBox(loadout.desc, wipHeader, loadout.patch)
	end
	return loadout
end

function processString(ptbString, loadout)
	local patchSub = "#patch#"
	local latestPatchSub = "#lpatch#"
	
	local ptbString = ptbString:gsub(patchSub, (loadout and loadout.patch) or cstr.empty):gsub(latestPatchSub, data.latestPatch.patch)
	
	return ptbString
end
--------------------------------------------------------------------------------

function subNames(loadout)
	local regexStrings = {"#pn", "#name"}
	if loadout.desc ~= nil then
		for _, regex in ipairs(regexStrings) do
			for m in loadout.desc:gmatch(regex) do
				loadout.desc = loadout.desc:gsub(regex, i(loadout.name))
			end
		end
	end
	return loadout
end

function subValues(loadoutObj)
	local regexString = "#pl%((%d)%)" -- looking and extracting number from "#pl(x)"
	if loadoutObj and loadoutObj.desc ~= nil then
		for m in loadoutObj.desc:gmatch(regexString) do --TODO the first index shouldn't be hardcoded due to history log (if the description will be copied, then it won't be the first)
			local currentRegexString = "#pl%(" .. tonumber(m) .. "%)" --you need to replace ONLY CURRENT INDEX, otherwise you'll get replaced all #pl(x) at once when going through the first time (i.e. the first tripplet will replace all #pl() in text
			loadoutObj.desc = loadoutObj.desc:gsub(currentRegexString, pl(loadoutObj, tonumber(m)))
			--mw.log(loadoutObj.desc)
		end
	end
	--mw.log("PL: " .. pl)
	return loadoutObj --result
end

function processElementValues(loadout)
	for pattern, value in pairs(loadout) do
		if pattern ~= "desc" then --skip the description itself
			if type(value) == types.table then --Handling multiple values
				local regexString = "#" .. pattern .. "%((%d)%)"
				
				for index, search in loadout.desc:gmatch(regexString) do
					local i = tonumber(index)
					local currentRegexString = "#" .. pattern .. "%(" .. tonumber(i) .. "%)"
					loadout.desc = loadout.desc:gsub(currentRegexString, (tostring(value[i]):gsub("%%", "%%%%")))
				end
			else --should be single value
				--the inner gsub must be in brackets as the function returns trwo values, parsed values and the second one count of replacements: gsub => parsedValues, countOfParsedvalues )
				--this means that if there is no percentage it returns 0, and the 4th parameter of gsub is n for how many replacement is supposed to be done.
				loadout.desc = loadout.desc:gsub("#" .. pattern, (tostring(value):gsub("%%", "%%%%"))) 
			end
		end
	end
	
	return loadout
end

function pl(loadoutObj, tripplet)
	tripplet = tonumber(tripplet)
	local index = 1 + ((tripplet - 1) * 3) --tripplet is an offset, +1 is indexing from 1 in LUA, * 3 is because every values are grouped by 3 values/tiers
	local unit = getUnitById(loadoutObj.units[tripplet]) --If unit is empty, then don't apply bold function
	local rarity = loadoutObj.rarity or 2
	return bclr(rarity, loadoutObj.values[index]) .. "/" .. bclr(rarity + 1, loadoutObj.values[index + 1]) .. "/" .. bclr(rarity + 2, loadoutObj.values[index + 2]) .. space .. ((unit ~= cstr.empty and b(unit)) or cstr.empty) --Units, Tripplet is an index in 'units' list
end

function getUnitById(id)
	local perksData = mw.loadData("Module:Datatable/Loadout" .. utils.lang())
	for _, unit in ipairs(perksData.units) do
		if unit.id == id then return unit.value end
	end
	return strings.unitNotFound
end

return p