Module:Various
Jump to navigation
Jump to search
local p = {}
local str = require("Module:Strings")
local utils = require("Module:Utils")
local _bothThemesStartingDlcId = 37 --Resident Evil™: PROJECT W
p.strings = {
characterNotFound = ibclr(6, "Character wasn't found." .. cstr.contact),
mapNotFound = ibclr(6, "Map wasn't found." .. cstr.contact),
noMapAchiev = ibclr(6, "This map doesn't have any achievement."),
noDesc = i("Description wasn't found"),
missingName = i("Missing name"),
missingCharType = 'Missing parameter ' .. bclr("orange", charType) .. '. Allowed values are "K" or "S" (without quotes).',
ptbHeader = "This description is based on the changes featured in the upcoming Patch: #patch#",
wipHeader = "This description is being worked on or will be changed soon in order to improve clarity.",
--events
anniversaryEvent = "Anniversary Event",
cosmeticRewards = "Cosmetic Rewards Event",
crossoverEvent = "Crossover Event",
eventTome = "Event Tome", --also used for as Event Tome link on main page
modifierTome = "Modifier Tome",
halloweenEvent = "Halloween Event",
lunarEvent = "Lunar Event",
miniEvent = "Mini-Event",
springEvent = "Spring Event",
summerEvent = "Summer Event",
winterEvent = "Winter Event",
communityChallenge = "Community Challenge",
communityChoiceEvent = "Community Choice Event",
doubleDR = "Double Daily Ritual Bloodpoints Event",
doubleRF = "Double Rift Fragments Event",
doubleXP = "Double XP Event",
matchXP = "Match XP Event",
fMOTDXP = "First Match of the Day Bonus XP Event",
tomeCommunityChallenge = "Tome Community Challenge",
bloodRush = "Blood Rush",
bloodHunt = "Blood Hunt",
bloodFeast = "Blood Feast",
bloodFury = "Blood Fury", --not used currently
fragmentFrenzy = "Fragment Frenzy",
fragmentFeast = "Fragment Feast",
fragmentFury = "Fragment Fury",
doublePlayerXP = "Double Player XP Event",
triplePlayerXP = "Triple Player XP Event",
newDlcReleased = "New DLC Released",
unknownDesc = bclr(16, "THIS EFFECTS OF THIS #element ARE UNKNOWN."), -- currently not used
retired = bclr(13, "THIS #element HAS BEEN RETIRED."),
mobile = bclr(6, "THIS #element IS ONLY AVAILABLE ON MOBILE."), -- currently not used
deprecated = bclr(5, "NO LONGER AVAILABLE IN THE BLOODWEB."), -- currently not used
notAvailable = bclr(8, "NO LONGER AVAILABLE."), -- currently not used
unused = bclr(8, "THIS #element IS UNUSED."), -- currently not used
decom = bclr(8, "THIS #element HAS BEEN DECOMMISSIONED."), -- currently not used
hidden = ibclr(6, "THIS #element IS HIDDEN"),
day = {
[1] = "day",
[2] = "days",
},
--dayOrder = #1#
killer = "Killer",
killers = "Killers",
surv = "Survivor",
survs = "Survivors",
icon = "Icon",
name = "Name",
desc = "Description",
adept = "Adept",
currentEvents = "Current Event(s)", --main page heading
event = "Event",
modifier = "Modifier",
gameMode = "Game Mode",
tome = "Tome", --used for tome page name, ex. "Tome 16 -- Existence"
new = "New",
patch = "Patch",
}
local strings = p.strings
if utils.lang() ~= cstr.empty and (counter or 0) < 1 then
counter = (counter or 0) + 1
strings = require("Module:Various" .. utils.lang()).strings
end
--------------
-- RARITIES --
--------------
p.rarity = {
[0] = {id = 0, name = "Unused"},
[1] = {id = 1, name = "Common"},
[2] = {id = 2, name = "Uncommon"},
[3] = {id = 3, name = "Rare"},
[4] = {id = 4, name = "Very Rare"},
[5] = {id = 5, name = "Ultra Rare"},
[6] = {id = 6, name = "Legendary", clr = 12},
[7] = {id = 7, name = "Teachable", clr = 6},
[8] = {id = 8, name = "Event", clr = 14},
[9] = {id = 9, name = "Artifact", clr = 15},
[10] = {id = 10, name = "Spiritual"},
[11] = {id = 11, name = "Limited", clr = 25},
[12] = {id = 12, name = "Craft-able & " .. utils.clr(25, "Limited"), techName = "Craft-able & Limited", clr = false},
[20] = {id = 20, name = "Retired", clr = 13},
[21] = {id = 21, name = "Decommissioned", clr = false},
}
p.elementStrings = {
items = "ITEM", --currently not used
offerings = "OFFERING", --currently not used
addons = "ADD-ON", --currently not used
perks = "PERK", --currently not used
achievements = "ACHIEVEMENT"
}
----------------------------------------------
------------
-- PRICES --
------------
p.elementCost = {
[1] = 2000, -- Common
[2] = 2500, -- Uncommon
[3] = 3250, -- Rare
[4] = 4000, -- Very Rare
[5] = 5000, -- Ultra Rare
[8] = 2000, -- Event
}
local elementType = cstr.empty
local elementTable = {}
local elementDescTable = {}
local function elementUpperString() return string.upper(elementType) end
local function elementCapitalised() return utils.capitalizeName(elementType) end
--Table used for mapping which string should use which style
p.elementStringMapper = {
elementNotFound = elementCapitalised,
elementDescNotFound = elementCapitalised,
unknownDesc = elementUpperString,
retired = elementUpperString,
mobile = elementUpperString,
deprecated = elementUpperString,
unused = elementUpperString,
decom = elementUpperString,
hidden = elementUpperString,
}
function setElementTable(elType)
local elementTypeList = {
addons = "Loadout",
items = "Loadout",
offerings = "Offerings",
achievements = "Achievements",
perks = "Perks"
}
local elementData = mw.loadData("Module:Datatable/" .. utils.capitalizeName(elementTypeList[elType]) .. utils.lang())
elementType = p.elementStrings[elType]
elementTable = elementData[elType]
elementDescTable = elementData[string.replace(elementType:lower(), '-', cstr.empty) .. "Descriptions"]
end
--this list is to indicate which event types should be recognised for auto-flagging loadout (being deprecated)
p.eventTypes = {
anniversaryEvent = "anniversaryEvent",
halloweenEvent = "halloweenEvent",
lunarEvent = "lunarEvent",
summerEvent = "summerEvent",
winterEvent = "winterEvent"
}
--Following strings are searched as a part of various string
--example: Anniversary Blood Rush => contains the string "Blood Rush" - this part gets redirected to appropriate page
local _eventList = {
strings.bloodRush,
strings.bloodHunt,
strings.bloodFeast,
strings.communityChoiceEvent
}
--List to be excluded as a link in Past Events section
local _excludedEventList = {
strings.doubleDR,
strings.doubleRF,
--strings.doublePlayerXP,
strings.doubleXP,
strings.matchXP,
strings.fMOTDXP,
}
--------------------------------------------------------------------------------
function wrapPtb(element)
if element.desc ~= nil then
local processedString = processString(strings.ptbHeader, element)
element.desc = ptb(element.desc, processedString, element.patch)
end
return element
end
function wrapWipBox(element)
if element.desc ~= nil then
local wipHeader = processString(strings.wipHeader, element)
element.desc = utils.wipBox(element.desc, wipHeader, element.patch)
end
return element
end
function processString(ptbString, element)
local data = require("Module:Datatable" .. utils.lang())
local patchSub = "#patch#"
local latestPatchSub = "#lpatch#"
local ptbString = ptbString:gsub(patchSub, (element and element.patch) or cstr.empty):gsub(latestPatchSub, data.latestPatch.patch)
return ptbString
end
--------------------------------------------------------------------------------
function p.getElementsByCategory(cat, elTable, charType)
local result = {}
cat = cat and string.split(cat, ',')
if cat[#cat] == "all" then
if charType then
return getAllCharTypeElements(charType, elTable)
end
for elName, el in pairs(elTable) do
local element = table.copy(el)
element.name = elName
table.add(result, element)
end
table.addRange(result, getAllCharTypeElements(charType, elTable))
return result
elseif cat[#cat] == "general" then
return getGeneralElementsByCharType(charType, elTable)
end
for elName, el in pairs(elTable or (elementType ~= cstr.empty and elementTable)) do
if (charType == nil or el.charType == charType or ((charType == 'S' and el.itemsCategory) or (charType == 'K' and el.killer))) then
local found = false
for _, searchedCat in ipairs(cat) do
if (searchedCat == "retired" and el.retired) or
(searchedCat == "hidden" and el.hidden) or
(searchedCat == "killer" and el.killer) or
(searchedCat == "unused" and (el.unused or el.unusedVisible)) or
(searchedCat == "decom" and el.decom) or
(searchedCat == "mobile" and el.mobile) or
(searchedCat == "deprecated" and el.deprecated) then
local element = table.copy(el)
element.name = element.name or elName
table.add(result, element)
break
else
if el.tags ~= nil then
for _, category in ipairs(el.tags) do
if category == searchedCat then
local element = table.copy(el)
element.name = element.name or elName
table.add(result, element)
found = true
break
end
end
end
end
if found then break end
end
end
end
return result
end
function p.getCountElementsByCategory(cat, elTable, charType)
local category = utils.resolveParameter(cat)
local charType = charType or utils.resolveParameter(cat, 2, true)
return #p.getElementsByCategory(category, elTable, charType)
end
function p.getElementsByNames(names, elTable)
local result = {}
elTable = elTable or (elementType ~= cstr.empty and elementTable)
names = names and string.split(names, ',')
for _, elName in ipairs(names) do
if elTable[elName] then
local element = table.copy(elTable[elName])
element.name = elName
table.add(result, element)
end
end
return result
end
function p.getElementsByRarities(searchedRarities, elTable)
local result = {}
local rarityObjs = {}
searchedRarities = type(searchedRarities) == types.string and string.split(searchedRarities, ',') or tonumber(searchedRarities) and {searchedRarities} or searchedRarities
for _, searchedRarity in ipairs(searchedRarities) do
for i, rar in pairs(p.rarity) do
if tonumber(searchedRarity) == i or searchedRarity == rar.name then --type(searchedRarity) == types.string and
rar.rarity = i
table.add(rarityObjs, rar)
break
end
end
end
for elName, el in pairs(elTable or (elementType ~= cstr.empty and elementTable)) do
if table.contains(table.get(rarityObjs, "rarity"), el.rarity) then
local element = table.copy(el)
element.name = elName
table.add(result, element)
end
end
return result
end
function p.getElementCost(el, raw)
return (raw and p.elementCost[el.rarity]) or
((p.elementCost[el.rarity] and utils.formatNum(p.elementCost[el.rarity], 0)) or " -") .. '<p style="margin: 4px">' .. file(utils.getIcon(ils.bpWhite), "56px") .. '</p>'
end
function getAllCharTypeElements(charType, elTable)
local result = {}
for elName, el in pairs(elTable) do
if (charType == nil or el.charType == charType) and not el.unused then
local element = table.copy(el)
element.name = element.name or elName
table.add(result, element)
end
end
return result
end
function getGeneralElementsByCharType(charType, elTable)
local result = {}
for elName, el in pairs(elTable) do
if not el.character and (el.charType == charType or charType == nil) and not el.unused then
local element = table.copy(el)
element.name = element.name or elName
result[elName] = element
table.add(result, element)
end
end
return result
end
function p.fillElementInfo(element)
if type(element.map) == types.number then
local mapsLogic = require("Module:Maps" .. utils.lang())
element.map = mapsLogic.getMapById(element.map)
end
if type(element.realm) == types.number then
local mapsLogic = require("Module:Maps" .. utils.lang())
element.realm = mapsLogic.getRealmById(element.realm)
end
if type(element.killer) == types.number then
local killersLogic = require("Module:Killers" .. utils.lang())
element.killer = killersLogic.getKillerById(element.killer)
end
if type(element.survivor) == types.number or type(element.surv) == types.number then
local survivorsLogic = require("Module:Survivors" .. utils.lang())
element.killer = survivorsLogic.getSurvivorById(element.survivor or element.surv)
end
end
--cat = category --this cannot be tested as usual, in order to pass the parameter in debug it needs to be passed like this: {args = {"category"}}
function p.getPastEventsTabber(cat)
cat = utils.resolveParameter(cat, 1, true)
local data = mw.loadData("Module:Datatable" .. utils.lang())
local tabberTable = {}
local catData = (cat and p.getElementsByCategory(cat, data.events)) or nil
local year
local tabberRow = {content = cstr.empty}
for _, event in ipairs(catData or data.events) do
local rDateFull = utils.IsFullDateTime(event.rDate)
local eDateFull = utils.IsFullDateTime(event.eDate)
local rDate = utils.standardiseDateObject(event.rDate)
local eDate = utils.standardiseDateObject(event.eDate)
local eventDateInfo = {rDateFull = rDateFull, eDateFull = eDateFull, rDate = rDate, eDate = eDate}
if not year then --first run
year = rDate.year
end
if year ~= rDate.year then
table.insert(tabberTable, tabberRow)
tabberRow = {content = cstr.empty}
year = rDate.year
end
tabberRow.header = year
local eventType = getEventType(event) --The Event type is used as a title for tooltip, mapped via tables at the top. If eventType is not evaluated and event.note is not present the Title is not mapped and tooltip won't appear
local eventIcon = file(utils.getIcon(event.icon), '64px', 'link=' .. getEventIconLink(event))
local eventDurationString = getEventDurationString(event, eventDateInfo)
local rowText = getEventNameWithLink(event)
tabberRow.content = tabberRow.content ..
nbullet .. space .. eventIcon .. space ..
(((eventType or event.note) and --if this condition is false then the Tooltip won't be present #EDIT: it will be always true now, as the eventType will always have a value (event name is now default value)
utils.tooltip(
rowText,
((eventType and b(eventType) .. br) or cstr.empty) ..
((event.img and br .. file(event.img, '250px', 'link=') ..br) or cstr.empty) ..
((event.note and small(event.note) .. br) or cstr.empty) ..
eventDurationString,
true, true)
) or rowText).. nl
--if rDateFull and utils.dateHasPassed(rDate) then
--else
--end
end
table.insert(tabberTable, tabberRow)
--lg(utils.getTabberFromTable(tabberTable))
return utils.getTabberFromTable(tabberTable)
end
function getEventIconLink(event)
for _, excludedEvent in ipairs(_excludedEventList) do
if string.find(event.name, excludedEvent) or event.name == excludedEvent then
return cstr.empty
end
end
for _, eventItem in ipairs(_eventList) do
if string.find(event.name, eventItem) then
return eventItem
end
end
return event.name
--if utils.pageExists(event.name) then --we should find better way thanrather than checking page existence
-- table.insert(_eventList, event.name)
--end
end
function getEventDurationString(event, eventDateInfo)
local result, period, length = cstr.empty, cstr.empty, cstr.empty
local joinS = ' - '
if eventDateInfo.rDateFull and eventDateInfo.eDateFull then
period = utils.toDate(eventDateInfo.rDate.timestamp, utils.timeFormat1) .. joinS .. utils.toDate(eventDateInfo.eDate.timestamp, utils.timeFormat1)
local eventLength = utils.getTimeDiffFormatting(os.difftime(eventDateInfo.eDate.timestamp, eventDateInfo.rDate.timestamp), "day") -- + 1 -- Events start always at 16:00 UTC so even though it covers one more day, the actual length is exactly 7 days for instance
length = brackets(utils.getDynamicString(eventLength .. space .. utils.getWord(strings.day, eventLength), dayOrder))
result = period .. space .. length
else
if eventDateInfo.rDate.fakeMonth or eventDateInfo.eDate.fakeMonth then
period = eventDateInfo.rDate.year
if eventDateInfo.rDate.year ~= eventDateInfo.eDate.year then
period = period .. joinS .. eventDateInfo.eDate.year
end
elseif eventDateInfo.rDate.fakeDay or eventDateInfo.eDate.fakeDay then
period = utils.resolveDateTime(event.rDate, true)
if eventDateInfo.rDate.month ~= eventDateInfo.eDate.month then
period = period .. joinS .. utils.resolveDateTime(event.eDate, true)
end
end
result = period
end
return note(result)
end
function getEventNameWithLink(event)
for _, excludedEvent in ipairs(_excludedEventList) do --excluding means we won't modify the name as a Link
if string.find(event.name, excludedEvent) or event.name == excludedEvent then
return event.name
end
end
--we have a list of string that if they are contained in whole string we Linkify that certain part
--Example: August 2022 Blood Rush => August 2022 [[Blood Rush]]
for _, eventItem in ipairs(_eventList) do
if string.find(event.name, eventItem) then
return event.name:gsub(eventItem, link(eventItem))
end
end
return link(event.name, event.displayName)
end
function getEventType(event)
event = table.copy(event)
if event.tags and #event.tags > 0 then
for _, tag in ipairs(event.tags) do
return strings[tag] --if there is at least one tag it will be used as a category
end
end
return event.name
end
function p.getCharTypeWord(el, plural)
if type(el) == types.string then
el = {charType = el}
end
if el and el.charType then
if el.charType == 'K' then
return (plural and strings.killers) or strings.killer
elseif el.charType == 'S' then
return (plural and strings.survs) or strings.surv
end
end
return false
end
--return: filename, [sucess]
function p.resolveCharacterThemeMusic(character, returnFilename)
local dlcs = require("Module:DLCs" .. utils.lang())
character.dlc = dlcs.getMainDlc(dlcs.getDlcs(character))
local fileConst = '_Theme_Music'
local survConst = '_Survivors'
local filename = cstr.empty
if not character.dlc then
filename = character.techName or character.name
else
filename = utils.resolveFileName(utils.CapitalizeName(utils.RemoveSpecialCharacters(character.dlc.name)), true, true)
end
filename = (filename or cstr.empty) .. ((not utils.isKiller(character) and survConst) or cstr.empty) .. fileConst
if character.dlc then
for _, theme in ipairs(dlcThemes) do
if theme.id == character.dlc.id then
filename = theme.fileName
end
end
end
local valid = utils.isValidFileName(filename, cstr.ogg)
return (valid and file(filename .. dot .. cstr.ogg)) or (returnFilename and filename .. dot .. cstr.ogg) or valid, (returnFilename and valid) or nil
end
function p.shouldHaveTheme(character)
local dlcs = require("Module:DLCs" .. utils.lang())
charDlc = dlcs.getMainDlc(dlcs.getDlcs(character))
return character.dlc and ((charDlc and charDlc.id and charDlc.id > _bothThemesStartingDlcId) or (type(character.dlc) == types.number and character.dlc > _bothThemesStartingDlcId)) or false
end
--element must have either survivor = # or killer = #
function p.getCharacter(element)
local data = require("Module:Datatable" .. utils.lang())
if element.survivor then
return utils.getCharacterById(element.survivor, data.survivors)
else
return utils.getCharacterById(element.killer, data.killers)
end
end
function p.getCharacterByName(name)
return utils.getCharacterByName(name)
end
function p.getCharacterFirstName(character, technical)
return utils.getCharacterFirstName(character, technical)
end
function p.getCharacterLastName(character)
character = utils.resolveParameter(character)
if not character.name then
character = p.getCharacterByName(character)
end
local isKiller = utils.isKiller(character)
local text = (isKiller and character.name) or character.shortName or character.name --if the char is killer then use their name, otherwise it's survivor, thus use shortName or name
if isKiller then return text end --if it's killer, then their nickname is already what it's supposed to return
text = string.split(text, cstr.space)
return text[#text] --return last word separated by space
end
function p.getCharactersPronoun(character)
local langs = require("Module:Languages")
return langs.evaluatePronoun(character)
end
function p.getCharPortrait(character, mainSize, hover, bgClr)
local langs = require("Module:Languages")
bgClr = bgClr or utils.resolveParameter(character, "bgClr", true) or utils.resolveParameter(character, 4, true) or nil
hover = utils.bool(hover or utils.resolveParameter(character, "hover", true) or utils.resolveParameter(character, 3, true) or false)
mainSize = tonumber(mainSize or utils.resolveParameter(character, "size", true) or utils.resolveParameter(character, 2, true)) or 250
character = (character and not character.args and character.name and character) or p.getCharacterByName(utils.resolveParameter(character, "character", true) or utils.resolveParameter(character, "name", true) or utils.resolveParameter(character))
local hoverString, techDisplayName
local displayName = p.getDisplayName(character)
if langs.nonEn() then
techDisplayName = p.getTechDisplayName(character)
end
local portraitFilename = --"K01 TheTrapper Portrait.png"
utils.getCharacterIdentifier(character) .. space ..
utils.RemoveSpecialCharacters(string.replace(techDisplayName or displayName, space, cstr.empty), true, true) .. space ..
"Portrait.png"
if hover then
local loadoutM = require("Module:Loadout" .. utils.lang())
local perkList = loadoutM.getPerkObjectsByOwner(character.name) or {}
utils.sortPerksByLevel(perkList)
local perkSize = mainSize * 0.192 --48 is 19.2% of 250% being a default sizing
hoverString =
'<div class = "charPortraitHoverWrapper ' .. (#displayName > 20 and "charProtraitLongName" or cstr.empty) .. ' flex flexColumn absolute">' .. nl ..
'<div class = "charPortraitName">' .. link(displayName, utils.specialUpperCase(displayName)) .. '</div>' .. nl .. --[[The Trapper|THE TRAPPER]]
((not table.empty(perkList) and '<div class = "charPortraitPerkWrapper flex">' .. nl) or cstr.empty)
for _, perk in ipairs(perkList) do
hoverString = hoverString ..
'<div class = "charPortraitPerk">' .. utils.assembleImage("sosPerk", perk.name, perkSize) .. '</div>' .. nl --{{#Invoke:Utils|assembleImage|sosPerk|Unnerving Presence|size=48}}
end
hoverString = hoverString ..
((not table.empty(perkList) and '</div>' .. nl) or cstr.empty) ..
'</div>' .. nl
else
hoverString = cstr.empty
end
result =
'<div style = "--defaultCharPortraitDimensions: ' .. mainSize .. 'px;" class = "charPortraitWrapper">' .. nl ..
'<div class = "charPortraitShadowBG"></div>' .. nl ..
'<div class = "charPortraitBg"></div>' .. nl ..
'<div class = "charPortraitRoleBg ' .. (bgClr or (utils.isKiller(character) and "killer" or "survivor")) .. '"></div>' .. nl ..
'<div class = "charPortraitImage flex flexCenter">' .. file(portraitFilename, "link=" .. displayName) .. '</div>' .. nl .. --[[File:K01 TheTrapper Portrait.png|The Trapper]]
--'<div class = "charPortraitImage flex flexCenter">' .. utils.getPoisitionedSprite(character.id, mainSize, "SurvivorPortraits") .. '</div>' .. nl .. --[[File:K01 TheTrapper Portrait.png|The Trapper]]
hoverString ..
'</div>' .. nl
return result
end
--<div class = "charPortraitWrapper">
-- <div class = "charPortraitShadowBG"></div>
-- <div class = "charPortraitBg"></div>
-- <div class = "charPortraitRoleBg killer"></div>
-- <div class = "charPortraitImage flex flexCenter">[[File:K01 TheTrapper Portrait.png|The Trapper]]</div>
-- <div class = "charPortraitHoverWrapper flex flexColumn absolute">
-- <div class = "charPortraitName">'''[[The Trapper|THE TRAPPER]]'''</div>
-- <div class = "charPortraitPerkWrapper flex">
-- <div class = "charPortraitPerk">{{#Invoke:Utils|assembleImage|sosPerk|Unnerving Presence|size=48}}</div>
-- <div class = "charPortraitPerk">{{#Invoke:Utils|assembleImage|sosPerk|Brutal Strength|size=48}}</div>
-- <div class = "charPortraitPerk">{{#Invoke:Utils|assembleImage|sosPerk|Agitation|size=48}}</div>
-- </div>
-- </div>
--</div>
function p.resolveCharactersTable(charType)
local data = require("Module:Datatable" .. utils.lang())
charType = utils.resolveParameter(charType, "charType", true) or utils.resolveParameter(charType)
local result = cstr.empty
for _, character in ipairs(charType == 'K' and data.killers or data.survivors) do
local displayName = p.getDisplayName(character)
result = result ..
'<div style = "display: inline-flex; flex-direction: column; text-align:center; margin-bottom: 35px;">' .. link(character.shortName or character.realName or character.name) .. (((utils.isKiller(character) or character.moniker) and displayName) or cstr.empty) .. nl ..
p.getCharPortrait(character, nil, false) .. nl ..
'</div>' .. nl
end
return '<div style = "color: #fff;">' .. result .. '</div>'
end
function p.resolveCharactersEntries(charType)
local data = require("Module:Datatable" .. utils.lang())
local various = require("Module:Various" .. utils.lang())
local loadoutM = require("Module:Loadout" .. utils.lang())
local result = cstr.empty
charType = utils.resolveParameter(charType, 1, true) or utils.resolveParameter(charType, "charType", true) or 'S'
for tempIndex, character in ipairs(charType == 'K' and data.killers or data.survivors) do
local currentEntry = cstr.empty
local charPerks = loadoutM.getPerkObjectsByOwner(character.name)
if charPerks then
utils.sortPerksByLevel(charPerks)
end
currentEntry =
'|+ ' .. various.getDisplayName(character) .. nl .. ntl .. nl ..
tl .. 'class = "center" rowspan = 3' .. tl .. various.getCharPortrait(character, 200, false) .. nl
if type(charPerks) == types.table then
for i, perk in ipairs(charPerks) do
currentEntry = currentEntry ..
hl .. img(perk.name, "32px") .. nl ..
hl .. link(perk.name) .. nl ..
((i < #charPerks and ntl .. nl) or cstr.empty)
end
end
result = result ..
'<div class = "entryTable">' .. nl ..
utils.wrapBasicTable(currentEntry, nil, nil, true) .. nl ..
'</div>' .. nl
end
result =
'<div style="display: flex; flex-flow: row wrap; justify-content:center;">' .. nl ..
result .. nl ..
'</div>' .. nl
return result
end
function p.getDisplayName(character)
return
(character.moniker and the(character) .. character.moniker) or
((character.isKiller or utils.isKiller(character)) and the(character) .. character.name) or
character.shortName or
character.name
end
--for subwikis
function p.getTechDisplayName(character)
return
(character.techMoniker and "The" .. space .. character.techMoniker) or
((character.isKiller or utils.isKiller(character)) and (character.techName and "The" .. space .. character.techName)) or
character.techShortName or
character.techName
end
--copy of utils version
function p.getCharsByDlc(dlc, charType)
local data = require("Module:Datatable" .. utils.lang())
local result = {}
local listTable = (charType == 'S' and data.survivors) or (charType == nil and data.survivors) or data.killers --if the charType is not set then set the table by default to survivors
for _, character in ipairs(listTable) do
if (type(character.dlc) == types.table and table.contains(character.dlc, dlc.id)) or character.dlc == dlc.id then
table.add(result, character)
end
end
if charType ~= nil then --if the charType is set, we need loop through only one table. Otherwise charType wasn't set in order to retrieve both types of characters from DLC
return result
end
for _, character in ipairs(data.killers) do --since the default table is survivor, we can hardcode killer table as a second table
if (type(character.dlc) == types.table and table.contains(character.dlc, dlc.id)) or character.dlc == dlc.id then
table.add(result, character)
end
end
return result
end
function getAchievImage(achievement, prefix)
if achievement and type(achievement) == types.table and achievement.image then
return achievement.image
end
return ((achievement and type(achievement) == types.table and achievement.name or type(achievement) == types.string) and
"Ach " .. utils.firstLetterLower((prefix or cstr.empty) .. utils.resolveFileName(type(achievement) == types.string and achievement or achievement.techName or achievement.name, false, true)) .. dot .. cstr.jpg) or cstr.empty
end
function getAchieveTableRow(achievement)
return (achievement and achievement.name and achievement.desc and achievement.image and
nl .. ntl .. nl .. tl .. file(achievement.image, "64px") .. nl .. hl .. achievement.name .. nl .. tl .. achievement.desc) or cstr.empty
end
function p.resolveCharacterAchievements(character)
character = p.getCharacterByName(utils.resolveParameter(character))
if not character then return false end
character.isKiller = utils.isKiller(character)
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
local result = cstr.empty
setElementTable("achievements")
if not character then return strings.characterNotFound end
result = result .. getAchieveTableRow(p.getAdeptAchievement(character)) --adding adept achievement
for achName, ach in pairs(dataAchiev.achievements) do
if (character.isKiller and ach.killer or ach.survivor) == character.id then
local achiev = table.copy(ach)
achiev.name = achiev.name or achName
achiev.image = getAchievImage(achiev)
p.postprocessAchievementDescription(achiev)
p.postprocessDescription(achiev)
result = result .. getAchieveTableRow(achiev)
end
end
result = hl .. strings.icon .. dhl .. strings.name .. dhl .. strings.desc .. result .. nl --adding header row
result = utils.wrapBasicTable(result)
return result
end
function p.getAdeptAchievement(character, cat)
setElementTable("achievements")
local dlcs = require("Module:DLCs" .. utils.lang())
local loM = require("Module:Loadout" .. utils.lang())
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
character.dlc = dlcs.getDlcByCharacter(character) --we need to know if the DLC got retracted, hence an achievement is retired
character.dlc = (#character.dlc == 1 and character.dlc[1]) or character.dlc
character.perks = loM.getPerkObjectsByOwner(character.name)
if character.perks then
utils.sortPerksByLevel(character.perks)
end
local isKiller = utils.isKiller(character)
local desc = (isKiller and dataAchiev.strings.adeptAchiev_killer) or dataAchiev.strings.adeptAchiev_surv
local adeptName = character.moniker or (character.useLastName and p.getCharacterLastName(character)) or p.getCharacterFirstName(character)
local techAdeptName = (character.useLastName and p.getCharacterLastName(character)) or p.getCharacterFirstName(character, true)
local achievement = {
name = strings.adept .. space .. adeptName,
desc = desc,
adeptName = adeptName,
isKiller = isKiller,
character = character,
diacritics = character.diacritics,
retired = (character.dlc and (character.dlc.retracted or character.dlc.achRetired)) or false,
image = getAchievImage(techAdeptName, "adept")
}
if not table.contains({"all", "adept"}, cat) then
p.postprocessAchievementDescription(achievement)
p.postprocessDescription(achievement)
end
return achievement
end
function getAdeptAchievements(charType, cat)
local data = require("Module:Datatable" .. utils.lang())
local elTable = charType == 'K' and data.killers or data.survivors
local result = {}
for _, character in ipairs(elTable) do
table.add(result, p.getAdeptAchievement(character, cat))
end
return #result > 0 and result or false
end
function p.resolveMapAchievements(map) --used on map Page
setElementTable("achievements")
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
local mapsLogic = require("Module:Maps" .. utils.lang())
local result = cstr.empty
local achievs = {}
map = mapsLogic.getMapByMapName(utils.resolveParameter(map))
if not map then return strings.mapNotFound end
map.realm = mapsLogic.getRealmByMap(map)
for _, achiev in ipairs(getMapsAchievements(map.id)) do
result = result .. getAchieveTableRow(achiev)
end
result = hl .. strings.icon .. dhl .. strings.name .. dhl .. strings.desc .. result .. nl --adding header row
result = utils.wrapBasicTable(result)
return result
end
function getMapAchievements(mapId)
local data = require("Module:Datatable" .. utils.lang())
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
local result = {}
for _, achiev in ipairs(dataAchiev.achievements) do
local mapIdList = (achiev.map and type(achiev.map) == types.number and {achiev.map}) or (achiev.map and type(achiev.map) == types.table and achiev.map) or {}
for _, id in ipairs(mapIdList) do
if (mapId and id == mapId) or (not mapId and id) then
achiev.image = getAchievImage(achiev)
table.add(result, achiev)
end
end
end
return result
end
function p.getMapAchievement(map)
setElementTable("achievements")
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
p.fillElementInfo(map) --fill realm info
local achievement = {
name = map.achievName,
desc = dataAchiev.strings.landmarkGenAchiev,
image = getAchievImage(map.techAchievName or map.achievName),
retired = map.retired or (map.realm and (map.realm.retired or map.achRetired)) or false,
map = map
}
p.fillElementInfo(achievement)
p.postprocessAchievementDescription(achievement)
p.postprocessDescription(achievement)
return achievement
end
function getMapsAchievements(mapId)
local data = require("Module:Datatable" .. utils.lang())
local result = {}
for _, map in ipairs(data.maps) do
if (mapId and map.id == mapId) or (not mapId and map.achievName) then
table.add(result, p.getMapAchievement(map))
end
end
table.addRange(result, getMapAchievements(mapId))
return result
end
function p.getAchievementDescriptionByName(achName)
local dataAchiev = require("Module:Datatable/Achievements" .. utils.lang())
achName = utils.resolveParameter(achName)
for _, ach in ipairs(dataAchiev.achievements) do
if ach.name == achName then
p.postprocessAchievementDescription(ach)
return ach.desc
end
end
return strings.noDesc
end
function p.getAchievementsByCategory(cat, charType)
setElementTable("achievements")
local dataAchiev = mw.loadData("Module:Datatable/Achievements" .. utils.lang())
local achievs = {}
if cat == "adept" or (cat == "all" and charType) then
table.addRange(achievs, getAdeptAchievements(charType, cat))
elseif cat == "retired" or cat == "all" then
table.addRange(achievs, getAdeptAchievements("S", cat))
table.addRange(achievs, getAdeptAchievements("K", cat))
end
if cat == "map" or cat == "retired" or cat == "all" then
table.addRange(achievs, getMapsAchievements())
end
table.addRange(achievs, p.getElementsByCategory(cat, dataAchiev.achievements, charType))
achievs = table.distinct(achievs)
if cat == "all" then return achievs end --in this case we have all we need
--utils.sortItemsByName(achievs)
for _, achiev in ipairs(achievs) do
p.fillElementInfo(achiev)
p.postprocessAchievementDescription(achiev, true)
p.postprocessDescription(achiev)
end
return achievs
end
function p.getAchievementsCount(cat, charType)
setElementTable("achievements")
local achData = mw.loadData("Module:Datatable/Achievements" .. utils.lang())
charType = charType or utils.resolveParameter(cat, 2, true)
cat = utils.resolveParameter(cat, 1)
local achievs = p.getAchievementsByCategory(cat, charType)
local excludedAchievs = {}
for achievName, achiev in pairs(achievs) do
if achiev.retired then
table.add(excludedAchievs, achievName)
end
end
return #achievs - #excludedAchievs
end
--hideSpecial is considered achievements that are hidden or retired
function p.resolveAchievementsByCategory(cat, charType, hideSpecial)
setElementTable("achievements")
hideSpecial = utils.bool(hideSpecial or utils.resolveParameter(cat, "hideSpecial", true) or utils.resolveParameter(cat, 3, true) or false)
charType = charType or utils.resolveParameter(cat, 2, true)
cat = utils.resolveParameter(cat, 1)
local achievs = p.getAchievementsByCategory(cat, charType)
utils.sortItemsByName(achievs)
local result = cstr.empty
for _, ach in ipairs(achievs) do
if
(not hideSpecial and not ach.retired) or
( ( cat ~= "retired"
and ((cat ~= "hidden" and not ach.hidden and not ach.retired) or (cat == "hidden" and ach.hidden and not ach.retired))
and ((cat ~= "map" and not ach.map and not ach.retired) or (cat == "map" and ach.map and not ach.retired))
)
or (cat == "retired" and ach.retired)
) then
result = result ..
ntl .. nl ..
hl .. file(getAchievImage(ach), "64px") .. nl ..
hl .. (ach.name or strings.missingName) .. nl ..
tl .. (ach.desc or strings.noDesc) .. nl
end
end
result = utils.wrapBasicTable(result, nil, nil, true)
return result
end
function p.postprocessAchievementDescription(achievement, skipPerks)
if achievement.character then
achievement.desc = string.replace(achievement.desc, "#char", link((achievement.isKiller and achievement.character.name) or achievement.character.shortName or achievement.character.name))
achievement.desc = string.replace(achievement.desc, "#pronoun", p.getCharactersPronoun(achievement.character))
end
if achievement.perks or (achievement.character and achievement.character.perks) then
local p = achievement.perks or achievement.character.perks
achievement.desc = string.replace(achievement.desc, "#p1", (skipPerks and utils.IconLink(p[1].name)) or utils.loadoutIconLink(p[1].name, nil, nil, {perk = p[1]})) --utils.IconLink(p[1].name))
achievement.desc = string.replace(achievement.desc, "#p2", (skipPerks and utils.IconLink(p[2].name)) or utils.loadoutIconLink(p[2].name, nil, nil, {perk = p[2]})) --utils.IconLink(p[2].name))
achievement.desc = string.replace(achievement.desc, "#p3", (skipPerks and utils.IconLink(p[3].name)) or utils.loadoutIconLink(p[3].name, nil, nil, {perk = p[3]})) --utils.IconLink(p[3].name))
end
if achievement.map and achievement.map.landmark then
achievement.desc = string.replace(achievement.desc, "#landmark", achievement.map.landmark)
end
if achievement.map and achievement.map.name then
achievement.desc = string.replace(achievement.desc, "#map", achievement.map.name)
end
end
function p.postprocessDescription(element)
if element.descProcessed then return end
--can be thrownchanged to loop, with flags = {"deprecated", "mobile", "notAvailable", "retired"}
if element.hidden then element.desc = string.replace(strings.hidden, "#element", p.elementStringMapper.decom()) .. dnl .. element.desc end
if element.unknownDesc then element.desc = string.replace(strings.unknownDesc, "#element", p.elementStringMapper.unknownDesc()) .. dnl .. element.desc end
if element.deprecated then element.desc = string.replace(strings.deprecated, "#element", p.elementStringMapper.deprecated()) .. dnl .. element.desc end --currently replace feature is not used in deprecated string
if element.mobile then element.desc = string.replace(strings.mobile, "#element", p.elementStringMapper.mobile()) .. dnl .. element.desc end
if element.notAvailable then element.desc = string.replace(strings.notAvailable, "#element", p.elementStringMapper.notAvailable()) .. dnl .. element.desc end
if element.unused then element.desc = string.replace(strings.unused, "#element", p.elementStringMapper.unused()) .. dnl .. element.desc end
if element.decom then element.desc = string.replace(strings.decom, "#element", p.elementStringMapper.decom()) .. dnl .. element.desc end
if element.retired then element.desc = string.replace(strings.retired, "#element", p.elementStringMapper.retired()) .. dnl .. element.desc end
--subNames(element)
if element.wip then --wip override ptb, having bigger urgency
wrapWipBox(element)
else
wrapPtb(element) --ptb should not appear if wip is true
end
element.descProcessed = true
end
function p.resolveCurrentEvents()
local currentEvents = p.getLiveEventsList()
local result = cstr.empty
if not currentEvents then return end
for i, event in ipairs(currentEvents) do
local eventTome = getEventTome(event)
local eventLink = (event.tome and not event.event and (event.modifier and strings.modifierTome or strings.tome) .. space .. event.tome .. ' - ' .. event.name) or event.name -- [Modifier] [[Tome 17 - Commitment]] OR simply [[event name]]
if not (eventTome and eventTome.name == event.name and event.type == "event" and eventTome.modifier) then
result = result ..
(i > 1 and tnl or cstr.empty) ..
'<big>' ..
b(center(
(
(event.type == "dlc" and strings.newDlcReleased .. colon .. space)
or (event.type ~= "patch" and link(eventLink, event.displayName))
or (event.type == "patch" and file(utils.getIcon(strings.patch), "48px") .. space .. strings.new .. space .. utils.getPatchLink(event)) .. space .. file(utils.getIcon(strings.patch), "48px")
or cstr.empty) ..
((event.tags and event.tags[1] and event.tags[1] ~= "modifier" and strings[event.tags[1]] and strings[event.tags[1]] ~= event.name and colon .. space .. strings[event.tags[1]]) or cstr.empty) ..
((eventTome and eventTome.event and ' + ' .. link(strings.eventTome .. space .. eventTome.tome .. ' - ' .. eventTome.name, strings.eventTome)) or cstr.empty)
.. brnl ..
(
(event.img and file(event.img, "400px", "center", "border", "link=" .. event.name))
or (event.tome and file("Tome" .. event.tome .. space .. (event.techName or event.name) .. " Banner" .. dot .. cstr.jpg, "400px", "center", "border", "link=" .. eventLink))
or cstr.empty
)
)
) ..
'</big>'
end
end
return '<div class="fpbox center">' .. nl ..
'<div class="heading">' .. strings.currentEvents .. '</div>' .. nl ..
result .. nl ..
'</div>'
end
function getEventTome(event)
local data = require("Module:Datatable" .. utils.lang())
for _, tome in ipairs(data.tomes) do
if tome.name == event.name then
return tome
end
end
return false
end
function p.getLiveEventsList()
local data = require("Module:Datatable" .. utils.lang())
local result = {}
for _, patch in ipairs(data.patches) do
patch.eDate = (utils.isFullDateTime(patch.rDate) and utils.addTime("day", 7, patch.rDate)) or nil --to simulate period when this annoucment should appear
if utils.isEventLive(patch) then
patch.type = "patch"
table.add(result, patch)
break
end
end
local dlcsLogic = require("Module:DLCs" .. utils.lang())
for _, dlc in ipairs(data.dlcs) do
dlc.eDate = (utils.isFullDateTime(dlc.rDate) and utils.addTime("day", 14, dlc.rDate)) or nil --to simulate period when this annoucment should appear
if utils.isEventLive(dlc) then
dlc.type = "dlc"
dlc.img = dlcsLogic.resolveDlcCapsuleFileNameByDlc(dlc, dlcsLogic.dlcMinIdForCapsuleCheck)
table.add(result, dlc)
end
end
for _, event in ipairs(data.events) do
if utils.isEventLive(event) then
event.type = "event"
table.add(result, event)
end
end
for _, tome in ipairs(data.tomes) do
if utils.isEventLive(tome) then
tome.type = "tome"
table.add(result, tome)
end
end
return (table.empty(result) and false) or result
end
function p.getTomeTable(tomeType)
tomeType = (type(tomeType) == types.string and tomeType) or utils.resolveParameter(tomeType, 1, true) or "default"
local result = cstr.empty
local groupedTomes = getGroupedTomes(tomeType)
for year, tomesInYear in spairs(groupedTomes) do
--if table.count(tomesInYear) > 0 then --if there is tomeType == event or modifier we need to skip years without such tomes
result = result ..
'<div class = "yearSectionWrapper divTable displayFlex flexColumn ' .. tomeType .. space .. string.replace("tomeYear#", "#", year) .. '">' ..
'<div class = "yearHeader displayFlex divTableHeader center">' .. big(year) .. '</div>' ..
'<div class = "tomesInYearWrapper displayFlex">'
for i = 1, 4 do
local tome = tomesInYear[i]
if tome and (tome.quarter == i or tome.dateObj.quarter == i) then
--for _, tome in ipairs(tomesInYear) do
-- if (tomeType == "default" and not (tome.event or tome.modifier))
-- or (tomeType == "event" and tome.event)
-- or (tomeType == "modifier" and tome.modifier) then
local tomePrefix = (tome.modifier and strings.modifier .. space or cstr.empty) .. (tome.event and strings.event .. space or cstr.empty)
result = result ..
'<div class = "tomeWrapper displayFlex flexColumn center">' ..
'<div class = "tomeIndex ' .. string.replace("tome#", '#', tome.tome or '0') .. ' divTableCell">' .. small(tomePrefix .. strings.tome .. space .. tome.tome) .. '</div>' ..
'<div class = "tomeName divTableCell">' .. link(tomePrefix .. strings.tome .. space .. tome.tome .. space .. dash .. space .. tome.name, string.upper(tome.name)) .. '</div>' ..
'<div class = "tomeImg divTableCell displayFlex flexCenter">' .. file((tome.event and "Event" or cstr.empty) .. "Tome" .. tome.tome .. space .. (tome.techName or tome.name) .. space .. "Banner.jpg", "350px") .. '</div>' ..
'<div class = "tomeRDate divTableCell">' .. utils.resolveDateTime(tome.rDate) .. '</div>' ..
'</div>'
else
result = result .. '<div class = "tomeWrapper blankSpace displayFlex flexColumn center"></div>'
end
-- end
end
result = result ..
'</div>' ..
'</div>'
--end
end
result =
'<div class = "displayFlex flexCenter>' ..
'<div class = "tomeTablekWrapper displayInlineFlex flexColumn">' .. result .. '</div>' ..
'</div>'
return result
end
function getGroupedTomes(tomeType)
local data = require("Module:Datatable" .. utils.lang())
local result = {}
local latestYear = 0
for _, tome in ipairs(data.tomes) do
if (tomeType == "default" and not (tome.event or tome.modifier))
or (tomeType == "event" and tome.event)
or (tomeType == "modifier" and tome.modifier) then
tome.dateObj = utils.standardiseDateObject(tome.rDate)
if not result[tome.dateObj.year] then
result[tome.dateObj.year] = {}
end
lg(tome.name .. space .. dash .. space .. tome.quarter)
result[tome.dateObj.year][tome.quarter or tome.dateObj.quarter] = tome
end
end
--utils.sortByKeys(result)
--for year, group in spairs(result) do
-- utils.sortByRDate(group)
--end
return result
end
function p.getCharacters_mainPage(charType, size)
size = tonumber(size or utils.resolveParameter(charType, "size", true) or utils.resolveParameter(charType, 2, true)) or 250
local data = require("Module:Datatable" .. utils.lang())
charType = utils.resolveParameter(charType, "charType", true) or utils.resolveParameter(charType)
local elTable
if charType ~= 'K' and charType ~= 'S' then
return strings.missingCharType
else
elTable = (charType == 'K' and data.killers) or data.survivors
end
local result = cstr.empty
for _, character in ipairs(elTable) do
result = result ..
p.getCharPortrait(character, size, true)
end
local header =
((charType == 'K' and the(strings.killers) .. space .. link(strings.killers) .. space .. img(strings.killer, '32px')) or
the(strings.survs) .. space .. link(strings.survs) .. space .. img(strings.surv, '32px'))
result =
--'<div class = "fpbox" style = "text-align: center;">' .. nl ..
--'<div class = "heading">' .. header .. '</div>' .. nl ..
'<div class = "charPortraitsMainPageWrapper">' .. nl ..
result ..
'</div>' .. nl --..
--'</div>'
return result
end
return p