Module:Infobox/Player

local lang = mw.getLanguage('en') local m_team = require('Module:Team') local TeamHistory = require('Module:Infobox/TeamHist').teamHist local util_args = require('Module:ArgsUtil') local util_cargo = require('Module:CargoUtil') local util_dpl = require('Module:DPLUtil') local util_game = require('Module:GameUtil') local util_html = require('Module:HtmlUtil') local util_infobox = require('Module:InfoboxUtil') local util_map = require('Module:MapUtil') local util_sentence = require("Module:SentenceUtil") local util_table = require('Module:TableUtil') local util_text = require("Module:TextUtil") local util_title = require("Module:TitleUtil") local util_vars = require('Module:VarsUtil') local i18n = require('Module:i18nUtil') local RoleList = require('Module:RoleList') local Country = require('Module:Country') local CountryList = require('Module:CountryList') local Region = require('Module:Region') local RegionList = require('Module:RegionList') local ChampionList = require('Module:ChampionList') local PlayerCurrentTeam = require('Module:PlayerCurrentTeam').main local IntroSentence = require('Module:IntroSentence/Player').main local PRStore = require('Module:PlayerPRStore')._main

local NOIMAGE = 'Unknown Infobox Image - Player.png'

local Infobox = require('Module:Infobox'):extends

Infobox.type = 'Player'

Infobox.LAYOUT = { tabs = 'PlayerTabsHeader', sections = { 'Background Information', 'Power Rankings', 'Competitive', 'Social Media & Links', 'Team History', 'Wiki Awards' }, contents = { { 'Name', 'Country', 'Nationality', 'Birthday', 'Died', 'Residency', 'ResidencyPrev' }, { 'All', 2018, 2019, 2020, 2021 }, { 'Team', 'Contract', 'Role', 'PreviousRole', 'CompIDs', 'SoloIDs' }, { 'social', social = 'wide' }, { 'teamhist', teamhist = 'wide' }, { 'wikiawards', wikiawards = 'wide' }, }, }

local DIRECT_STORE = { ID = 'id', Stream = 'stream', Twitter = 'twitter', Facebook = 'facebook', Askfm = 'askfm', Reddit = 'reddit', Youtube = 'youtube', Weibo = 'weibo', Vk = 'vk', Instagram = 'instagram', IsRetired = 'isretired', }

local AWARD_ARG_ORDER = { 'year', 'award', 'place', 'file' }

local h = {} -- helper functions local p = {} function p.main(frame) local args = util_args.merge return Infobox(args):run end

function Infobox:castArgs(args) args.role = RoleList(args.role, { sub = util_args.castAsBool(args.checkboxIsSub) }) args.favchamps = ChampionList(util_args.numberedArgsToTable(args, 'favchamp')) args.residency = Region(args.residency) args.res_prev1 = Region(args['residency-prev1']) args.res_prev2 = Region(args['residency-prev2']) args.res_prev = RegionList(util_args.numberedArgsToTable(args, 'residency-prev')) args.nationality = CountryList(args.nationality or args.country) args.country = Country(args.country) -- on Fortnite wiki we always do nationality args.isretiredplayer = util_args.castAsBool(args.isretiredplayer) args.isretired = util_args.castAsBool(args.isretired) args.islookingforduo = util_args.castAsBool(args.islookingforduo) args.islookingfortrio = util_args.castAsBool(args.islookingfortrio) util_map.arrayInPlace(args, h.castArgAwards) end

function h.castArgAwards(args) args.medals = util_args.splitArgs(args.medals, AWARD_ARG_ORDER, ';;;') return args.medals end

function Infobox:getProcessed(args) if util_args.castAsBool(args.checkboxAutoTeams) then args.team = nil args.team2 = nil end local processed = { pagename = mw.title.getCurrentTitle.text, bday = h.getBirthdayAndAgeIfAppropriate(args), died = h.getDeathDateIfNeeded(args), lc = args.id and lang:lcfirst(args.id) == args.id, hasAutoTeams = util_args.castAsBool(args.checkboxAutoTeams), image = h.getImage(args), isLowContent = util_args.castAsBool(args.low_content), redirects = util_dpl.whatRedirectsHere(nil, { notuses = 'Template:NoDPL/PlayerRedirects' }), PR = PRStore(args.id or mw.title.getCurrentTitle.baseText), }	processed.entity = processed.lc and util_text.lcfirst(processed.pagename) or processed.pagename local teamhist, last = TeamHistory(args) processed.teams = h.getTeamsTable(args, processed, last) processed.teamhist = not processed.hasAutoTeams and teamhist processed.roleLast = h.getCargoLastRole(args, processed) processed.resPrevList = h.getResPrevList(args, processed.teams, processed.hasAutoTeams) return processed end

function h.getImage(args) if not util_args.castAsBool(args.checkboxAutoImage) then return util_infobox.getFile(args.image, NOIMAGE) end local image = h.queryForImage(args) return image or NOIMAGE end

function h.getBirthdayAndAgeIfAppropriate(args) local bday = util_infobox.makeBday(args.birth_date_year, args.birth_date_month, args.birth_date_day) if args.died then bday.age = nil bday.displayandage = bday.display end return bday end

function h.getDeathDateIfNeeded(args) if not args.died then return {} end return util_infobox.makeBday(args.birth_date_year, args.birth_date_month, args.birth_date_day, args.died) end

function h.getTeamsTable(args, processed, last) if processed.hasAutoTeams then return PlayerCurrentTeam(mw.title.getCurrentTitle.text) end local teams = h.getLegacyTeams(args, processed) teams.last = last or {} return teams end

function h.getLegacyTeams(args, processed) local ret = util_map.inPlace(		util_args.numberedArgsToTable(args, 'team') or {},		h.getOneLegacyTeam, args, processed	) return ret end

function h.getOneLegacyTeam(team, args, processed) local ret = { team = m_team.teamlinkname(team), role = args.role, sub = util_args.castAsBool(args.checkboxIsSub), }	return ret end

function h.getCargoLastRole(args, processed) if not processed.hasAutoTeams then return args.role end -- role could be nil if player has 0 team entries if not processed.teams.last.RoleList then return args.role end return processed.teams.last.RoleList:_or(args.role) end

function h.getResPrevList(args, teams, hasAutoTeams) if not hasAutoTeams then return args.res_prev end if #teams.resPrevList == 0 then return RegionList end return RegionList(util_table.concat(teams.resPrevList)) end

function Infobox:getDisplay(args, processed) local display = self:super('getDisplay', args, processed) local tbl = { title = args.id or processed.pagename, image = not processed.isLowContent and processed.image, notice = h.getNotice(args), -- background info Name = args.name and (args.name .. (args.nativename and (' (%s)'):format(args.nativename) or '')), Nationality = args.nationality:flairs{sep=' '}, Birthday = processed.bday.displayandage, Died = processed.died.displayandage, Residency = args.residency:flair, ResidencyPrev = processed.resPrevList:flairs{sep=' '}, -- competitive Server = args.server, Team = h.getCurrentTeam(processed.teams), Contract = h.getContract(processed.teams), Role = args.role:flairs{len='role'}, CompIDs = util_table.concatFromArgs(args, 'compID',', '), SoloIDs = args.ids, -- social teamhist = processed.teamhist, --wikiawards = h.getAwards(args), class = h.getClass(args, processed) }	h.mergePowerRankingsIntoDisplay(display, processed.PR.display) return Infobox.mergeDisplay(display, tbl) end

function h.mergePowerRankingsIntoDisplay(display, pr) for _, tag in ipairs(pr) do		display[tag] = pr[tag].Score end end

function h.getAwards(args) local ret = {} util_vars.log(args.medals) for _, award in ipairs(args.medals) do		if not award.file then ret[#ret+1] = (''):format(award.award, award.year, award.place) else ret[#ret+1] = ('%s'):format(award.file) end end return util_table.concat(ret, ' &#8226; ') end

function h.queryForImage(args) local query = { tables = { 'PlayerRedirects=PR', 'PlayerImages=PI', 'Tournaments=T', },		join = { 'PR.AllName=PI.Link', 'PI.Tournament=T.OverviewPage', },		where = h.getImageWhere(args), fields = { 'PI.FileName' }, orderBy = 'COALESCE(PI.SortDate, T.DateStartFuzzy, T.Date) DESC', }	return util_cargo.getOneResult(query) end

function h.getImageWhere(args) local where = { ('PR._pageName="%s"'):format(mw.title.getCurrentTitle.text), ('PI._pageName IS NOT NULL'), ('PI.IsProfileImage="1"'), }	return where end

function h.getNotice(args) -- args.died is not a boolean if args.died then return i18n.print('notice_deceased') end if args.islookingforduo then return i18n.print('notice_lookingForDuo') end if args.islookingfortrio then return i18n.print('notice_lookingForTrio') end if args.isretiredplayer then return i18n.print('notice_retiredPlayer') end if args.isretired then return i18n.print('notice_retiredCompetition') end return nil end

function h.getCurrentTeam(teams) if #teams == 0 then return nil end return util_table.concat(		util_map.extractField(teams, 'team', m_team.rightmediumlinked),		' '	) end

function h.getContract(teams) if #teams == 0 then return nil end if not teams.contractDates then return nil end if #teams == 1 then return h.getContractDateFromFirstTeam(teams) end -- if they are on two teams but it's one org, we just show the date, nothing else -- but if they're on more than one org then we need to show a team icon next to the contract date local allSisterTeams = h.getListOfSisterTeamPages(teams) if #allSisterTeams == 1 then return h.getContractDateFromFirstTeam(teams) end return h.getAllContracts(teams) end

function h.getContractDateFromFirstTeam(teams) return teams.contractDates[teams[1].SisterTeamPage] end

function h.getAllContracts(teams) local contracts = {} for _, team in ipairs(teams) do		local contract = teams.contractDates[team.SisterTeamPage] if contract then contracts[#contracts+1] = ('%s%s'):format(				m_team.onlyimagelinked(team.team),				contract			) end end if #contracts == 0 then return nil end return util_table.concat(contracts, ' ') end

function h.getListOfSisterTeamPages(teams) local sisterTeamsUsed = {} local allSisterTeams = {} for _, team in ipairs(teams) do		if not sisterTeamsUsed[team.SisterTeamPage] then allSisterTeams[#allSisterTeams+1] = team.SisterTeamPage sisterTeamsUsed[team.SisterTeamPage] = true end end return allSisterTeams end

function h.getClass(args, processed) local listOfClasses = { processed.hasAutoTeams and 'infobox-player-narrow', processed.isLowContent and 'infobox-low-content', }	return util_table.concat(listOfClasses, ' ') end

function Infobox:getCargo(args, processed) local cargo = self:super('getCargo', args, processed) cargo[#cargo+1] = h.getPlayersCargo(args, processed) util_table.mergeArrays(		cargo,		h.getPlayerLeagueHistory(args)	) return cargo end

function h.getPlayersCargo(args, processed) local idlist = mw.clone(processed.redirects) idlist[#idlist+1] = processed.pagename local ret = { _table = 'Players', IDList = table.concat(idlist,','), OverviewPage = mw.title.getCurrentTitle.text, FortniteID = args.fortnite_id or mw.title.getCurrentTitle.text, Image = h.getImageCargo(args, processed), Name = args.name, Player = processed.entity, NativeName = args.nativename, NameAlphabet = args.namealphabet, NameFull = args.name and (args.name .. (args.nativename and (' (%s)'):format(args.nativename) or '')), Country = args.country, Nationality = args.nationality, NationalityPrimary = args.nationality:first, Age = processed.bday.age or '', Birthdate = processed.bday.store or '', ResidencyFormer = args['residency-prev1'], Team = processed.teams[1] and processed.teams[1].team, Team2 = processed.teams[2] and processed.teams[2].team, TeamSystem = 'PC', Team2System = 'PC', Residency = args.residency, Role = args.role, FavChamps = util_table.concatFromArgs(args, 'favchamp', ','), TeamLast = processed.teams.last and processed.teams.last.team, RoleLast = processed.roleLast, IsSubstitute = args.checkboxIsSub, IsLowercase = processed.lc, IsAutoTeam = args.checkboxAutoTeams, SoloqueueIds = args.ids, IsPersonality = args.page_type == 'Personality', IsLowContent = processed.isLowContent, IsLookingForDuo = args.islookingforduo, IsLookingForTrio = args.islookingfortrio }	h.addUnprocessedArgs(ret, args) return ret end

function h.getImageCargo(args, processed) if util_args.castAsBool(args.checkboxAutoImage) then return nil end if processed.image == NOIMAGE then return nil end if not processed.image then return nil end return processed.image:gsub('_', ' ') end

function h.addUnprocessedArgs(tbl, args) for k, v in pairs(DIRECT_STORE) do		tbl[k] = args[v] end end

function h.getPlayerLeagueHistory(args) if util_args.castAsBool(args.noplh) then return {} end if not util_game.store_player_league_history then return {} end local plhTable = require('Module:PlayerLeagueHistory')._main(mw.title.getCurrentTitle.text) return plhTable end

function Infobox:getDisambigSentence(args, processed) -- we can't store "now known as" here but we can store everything else -- the "now known as" text is going to have to change, but that's ok maybe local replacements = { RESIDENCY = args.residency:image, LINK = util_text.intLinkOrText(mw.title.getCurrentTitle.text), -- TODO: should this, actually be country...? NATIONALITY = args.country:exists and args.country:get('adjective'), FORMER = not processed.teams[1] and i18n.default('former') or '', ROLE = processed.roleLast:sentence, TEAM = processed.teams[1] and m_team.rightmediumlinked(processed.teams[1].team), -- NOW_KNOWN_AS = row.CurrentName and i18n.default('nowKnownAs', row.CurrentName) or '', }	return util_sentence.makeReplacements(i18n.default('disambigSentence'), replacements) end

function Infobox:getVariables(args, processed) local variables = self:super('getVariables', args, processed) local tbl = { suppressorgnavbox = args.checkboxSuppressOrgNavbox, introSentence = h.getIntroSentence(args, processed, 'Display'), description = h.getIntroSentence(args, processed, 'Description'), checkboxAutoTeams = args.checkboxAutoTeams, residency = args.residency:get, isretired = args.isretired or args.isretiredplayer, current_id = processed.entity, }	local i = 2 repeat thisteam = 'team' .. i		tbl[thisteam] = args[thisteam] and m_team.teamlinkname(args[thisteam]) i = i + 1 until(not args[thisteam]) return util_table.merge(variables, tbl) end

function h.getIntroSentence(args, processed, sentenceType) local data = mw.clone(args) local name = mw.text.split(args.name or '', ' ') data.firstname = table.remove(name, 1) data.lastname = table.concat(name, ' ') data.lastteam = processed.teams.last.team data.role = args.role:_or(processed.roleLast) data.teamStr = args.team and m_team.teamlinkname(args.team) data.isasub = util_args.castAsBool(args.checkboxIsSub) data.ispersonality = args.page_type == 'Personality' data.page_type = args.page_type data.isretired = util_args.castAsBool(args.isretired) data.lastteampresent = h.getLastTeamPresent(args, processed) data.currentTeamList = processed.teams data.hasAutoTeams = processed.hasAutoTeams return IntroSentence(data, sentenceType) end

function h.getLastTeamPresent(args, processed) if processed.teams and #processed.teams > 0 then return true end return processed.teams.last.date and processed.teams.last.date:find('Present') end

function Infobox:getCategories(args, processed) if util_args.castAsBool(args.pronly) then return { 'Power Ranking Player Pages' }	end local tbl = { 'Players', args.residency:exists and args.residency:get('adjective') .. ' Residents', not args.role:exists and 'Players Without Role', h.getSuspendedCategory(args, processed), h.isAFreeAgent(args, processed) and 'Free Agents', util_args.castAsBool(args.isretired) and 'Retired Players', args.birth_date_year and 'Players Born In ' .. args.birth_date_year, args.role:has(nil, 'Coach') and 'Coaches', processed.isLowContent and 'LowContent', }	if args.country:exists then if args.page_type == 'Personality' then tbl[#tbl+1] = ('%s Personalities'):format(args.country:get('adjective')) else tbl[#tbl+1] = 'Players Born in ' .. args.country:name{the=true} end end for _, region in ipairs(processed.resPrevList) do		tbl[#tbl+1] = ('Former %s Residents'):format(region:get('adjective')) end return tbl end

function h.isAFreeAgent(args, processed) if not util_args.castAsBool(args.checkboxAutoTeams) then if args.team then return false end if util_args.castAsBool(args.isretired) then return false end return true end return not h.getCurrentTeam(processed.teams) end

function h.getSuspendedCategory(args, processed) if processed.teams.last.team ~= 'Suspended' then return false end if not processed.teams.last.date then return false end if not processed.teams.last.date:find('Present') then return false end return 'Suspended Players' end

return p