From eed51a6d97fb8f320b8ec249c616f6dbd89eb0d0 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Mon, 26 Aug 2024 17:20:16 +0200 Subject: [PATCH 1/6] feat(match2): deadlock setup --- .../get_match_group_copy_paste_wiki.lua | 57 ++++++ .../deadlock/match_group_input_custom.lua | 181 ++++++++++++++++++ .../match2/wikis/deadlock/match_summary.lua | 173 +++++++++++++++++ 3 files changed, 411 insertions(+) create mode 100644 components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua create mode 100644 components/match2/wikis/deadlock/match_group_input_custom.lua create mode 100644 components/match2/wikis/deadlock/match_summary.lua diff --git a/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua new file mode 100644 index 00000000000..831150595e9 --- /dev/null +++ b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua @@ -0,0 +1,57 @@ +--- +-- @Liquipedia +-- wiki=deadlock +-- page=Module:GetMatchGroupCopyPaste/wiki +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Array = require('Module:Array') +local Class = require('Module:Class') +local Logic = require('Module:Logic') +local Lua = require('Module:Lua') + +local BaseCopyPaste = Lua.import('Module:GetMatchGroupCopyPaste/wiki/Base') + +---@class DeadlockMatch2CopyPaste: Match2CopyPasteBase +local WikiCopyPaste = Class.new(BaseCopyPaste) + +local INDENT = WikiCopyPaste.Indent + +function WikiCopyPaste.getMatchCode(bestof, mode, index, opponents, args) + local showScore = Logic.nilOr(Logic.readBoolOrNil, bestof == 0) + + local lines = Array.extend( + '{{Match', + Logic.readBool(args.needsWinner) and INDENT .. '|winner=' or nil, + Array.map(Array.range(1, opponents), function(opponentIndex) + return INDENT .. '|opponent' .. opponentIndex .. '=' .. WikiCopyPaste.getOpponent(mode, showScore) + end), + Logic.readBool(args.hasDate) and { + INDENT .. '|date=', + INDENT .. '|finished=', + INDENT .. '|twitch=|youtube=' + } or nil, + Array.map(Array.range(1, bestof), function(mapIndex) + return WikiCopyPaste._getMapCode(mapIndex) + end), + '}}' + ) + + return table.concat(lines, '\n') +end + +---@param mapIndex integer +---@return string +function WikiCopyPaste._getMapCode(mapIndex) + return table.concat(Array.extend( + INDENT .. '|map' .. mapIndex .. '={{Map|length=|winner=|vod=', + INDENT .. INDENT .. '|team1side=', + INDENT .. INDENT .. '|t1h1=|t1h2=|t1h3=|t1h4=|t1h5=|t1h6=', + INDENT .. INDENT .. '|team2side=', + INDENT .. INDENT .. '|t2h1=|t2h2=|t2h3=|t2h4=|t2h5=|t2h6=', + INDENT .. '}}' + ), '\n') +end + +return WikiCopyPaste diff --git a/components/match2/wikis/deadlock/match_group_input_custom.lua b/components/match2/wikis/deadlock/match_group_input_custom.lua new file mode 100644 index 00000000000..366e3f56845 --- /dev/null +++ b/components/match2/wikis/deadlock/match_group_input_custom.lua @@ -0,0 +1,181 @@ +--- +-- @Liquipedia +-- wiki=deadlock +-- page=Module:MatchGroup/Input/Custom +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Array = require('Module:Array') +local FnUtil = require('Module:FnUtil') +local HeroNames = mw.loadData('Module:HeroNames') +local Lua = require('Module:Lua') +local Operator = require('Module:Operator') +local Streams = require('Module:Links/Stream') +local Table = require('Module:Table') + +local MatchGroupInputUtil = Lua.import('Module:MatchGroup/Input/Util') + +local OPPONENT_CONFIG = { + resolveRedirect = true, + pagifyTeamNames = true, + pagifyPlayerNames = true, + maxNumPlayers = 10, +} + +local MatchFunctions = {} +local MapFunctions = {} + +local CustomMatchGroupInput = {} + +---@param match table +---@param options? {isMatchPage: boolean?} +---@return table +function CustomMatchGroupInput.processMatch(match, options) + local finishedInput = match.finished --[[@as string?]] + local winnerInput = match.winner --[[@as string?]] + Table.mergeInto(match, MatchGroupInputUtil.readDate(match.date)) + + local opponents = Array.mapIndexes(function(opponentIndex) + return MatchGroupInputUtil.readOpponent(match, opponentIndex, OPPONENT_CONFIG) + end) + local games = MatchFunctions.extractMaps(match, opponents) + match.bestof = MatchGroupInputUtil.getBestOf(match.bestof, games) + + local autoScoreFunction = MatchGroupInputUtil.canUseAutoScore(match, games) + and MatchFunctions.calculateMatchScore(games) + or nil + + Array.forEach(opponents, function(opponent, opponentIndex) + opponent.score, opponent.status = MatchGroupInputUtil.computeOpponentScore({ + walkover = match.walkover, + winner = match.winner, + opponentIndex = opponentIndex, + score = opponent.score, + }, autoScoreFunction) + end) + + match.finished = MatchGroupInputUtil.matchIsFinished(match, opponents) + + if match.finished then + match.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponents) + match.walkover = MatchGroupInputUtil.getWalkover(match.resulttype, opponents) + match.winner = MatchGroupInputUtil.getWinner(match.resulttype, winnerInput, opponents) + MatchGroupInputUtil.setPlacement(opponents, match.winner, 1, 2) + elseif MatchGroupInputUtil.isNotPlayed(winnerInput, finishedInput) then + match.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponents) + match.winner = nil + end + + MatchGroupInputUtil.getCommonTournamentVars(match) + + match.stream = Streams.processStreams(match) + match.extradata = MatchFunctions.getExtraData(match) + + match.games = games + match.opponents = opponents + + return match +end + +---@param match table +---@param opponents table[] +---@return table[] +function MatchFunctions.extractMaps(match, opponents) + local maps = {} + for key, map in Table.iter.pairsByPrefix(match, 'map', {requireIndex = true}) do + local finishedInput = map.finished --[[@as string?]] + local winnerInput = map.winner --[[@as string?]] + + map.map = nil + map.participants = MapFunctions.getParticipants(map, opponents) + map.extradata = MapFunctions.getExtraData(map) + + map.finished = MatchGroupInputUtil.mapIsFinished(map) + local opponentInfo = Array.map(opponents, function(_, opponentIndex) + local score, status = MatchGroupInputUtil.computeOpponentScore({ + walkover = map.walkover, + winner = map.winner, + opponentIndex = opponentIndex, + score = map['score' .. opponentIndex], + }, MapFunctions.calculateMapScore(map.winner, map.finished)) + return {score = score, status = status} + end) + + map.scores = Array.map(opponentInfo, Operator.property('score')) + if map.finished or MatchGroupInputUtil.isNotPlayed(map.winner, finishedInput) then + map.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponentInfo) + map.walkover = MatchGroupInputUtil.getWalkover(map.resulttype, opponentInfo) + map.winner = MatchGroupInputUtil.getWinner(map.resulttype, winnerInput, opponentInfo) + end + + table.insert(maps, map) + match[key] = nil + end + + return maps +end + +CustomMatchGroupInput.processMap = FnUtil.identity + +---@param maps table[] +---@return fun(opponentIndex: integer): integer +function MatchFunctions.calculateMatchScore(maps) + return function(opponentIndex) + return MatchGroupInputUtil.computeMatchScoreFromMapWinners(maps, opponentIndex) + end +end + +---@param match table +---@return table +function MatchFunctions.getExtraData(match) + return { + comment = match.comment, + } +end + +---@param map table +---@return table +function MapFunctions.getExtraData(map) + local extraData = { + comment = map.comment, + team1side = map.team1side, + team2side = map.team2side, + } + + return extraData +end + +---@param map table +---@param opponents table[] +---@return table +function MapFunctions.getParticipants(map, opponents) + local participants = {} + local getCharacterName = FnUtil.curry(MatchGroupInputUtil.getCharacterName, HeroNames) + + for opponentIndex in ipairs(opponents) do + for _, hero, playerIndex in Table.iter.pairsByPrefix(map, 't' .. opponentIndex .. 'h', {requireIndex = true}) do + participants[opponentIndex .. '_' .. playerIndex] = { + character = getCharacterName(hero), + } + end + end + + return participants +end + +---@param winnerInput string|integer|nil +---@param finished boolean +---@return fun(opponentIndex: integer): integer? +function MapFunctions.calculateMapScore(winnerInput, finished) + local winner = tonumber(winnerInput) + return function(opponentIndex) + -- TODO Better to check if map has started, rather than finished, for a more correct handling + if not winner and not finished then + return + end + return winner == opponentIndex and 1 or 0 + end +end + +return CustomMatchGroupInput diff --git a/components/match2/wikis/deadlock/match_summary.lua b/components/match2/wikis/deadlock/match_summary.lua new file mode 100644 index 00000000000..8e91258268e --- /dev/null +++ b/components/match2/wikis/deadlock/match_summary.lua @@ -0,0 +1,173 @@ +--- +-- @Liquipedia +-- wiki=deadlock +-- page=Module:MatchSummary +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Abbreviation = require('Module:Abbreviation') +local Array = require('Module:Array') +local CharacterIcon = require('Module:CharacterIcon') +local FnUtil = require('Module:FnUtil') +local DateExt = require('Module:Date/Ext') +local Icon = require('Module:Icon') +local Logic = require('Module:Logic') +local Lua = require('Module:Lua') +local Table = require('Module:Table') + +local DisplayHelper = Lua.import('Module:MatchGroup/Display/Helper') +local MatchSummary = Lua.import('Module:MatchSummary/Base') + +local SIZE_HERO = '57x32px' +local ICONS = { + winner = Icon.makeIcon{iconName = 'winner', color = 'forest-green-text', size = 'initial'}, + loss = Icon.makeIcon{iconName = 'loss', color = 'cinnabar-text', size = 'initial'}, + empty = '[[File:NoCheck.png|link=|16px]]', +} + +local CustomMatchSummary = {} + +---@param args table +---@return Html +function CustomMatchSummary.getByMatchId(args) + return MatchSummary.defaultGetByMatchId(CustomMatchSummary, args, {width = '400px', teamStyle = 'bracket'}) +end + +---@param match MatchGroupUtilMatch +---@param footer MatchSummaryFooter +---@return MatchSummaryFooter +function CustomMatchSummary.addToFooter(match, footer) + return MatchSummary.addVodsToFooter(match, footer) +end + +---@param match MatchGroupUtilMatch +---@return MatchSummaryBody +function CustomMatchSummary.createBody(match) + local body = MatchSummary.Body() + + if match.dateIsExact or match.timestamp ~= DateExt.defaultTimestamp then + body:addRow(MatchSummary.Row():addElement( + DisplayHelper.MatchCountdownBlock(match) + )) + end + + Array.forEach(Array.map(match.games, CustomMatchSummary._createGame), FnUtil.curry(body.addRow, body)) + + return body +end + +---@param participants table +---@param opponentIndex integer +---@return table +function CustomMatchSummary._getHeroesForOpponent(participants, opponentIndex) + local characters = {} + for _, participant in Table.iter.pairsByPrefix(participants, opponentIndex .. '_') do + table.insert(characters, participant.character) + end + return characters +end + +---@param game MatchGroupUtilGame +---@param gameIndex integer +---@return MatchSummaryRow +function CustomMatchSummary._createGame(game, gameIndex) + local row = MatchSummary.Row() + local extradata = game.extradata or {} + + row:addClass('brkts-popup-body-game') + :css('font-size', '80%') + :css('padding', '4px') + + local function makeCharacterDisplay(opponentIndex) + return CustomMatchSummary._createCharacterDisplay( + CustomMatchSummary._getHeroesForOpponent(game.participants, opponentIndex), + extradata['team' .. opponentIndex .. 'side'], + opponentIndex == 2 + ) + end + + row:addElement(makeCharacterDisplay(1)) + row:addElement(CustomMatchSummary._createCheckMark(game.winner, 1)) + row:addElement(mw.html.create('div') + :addClass('brkts-popup-body-element-vertical-centered') + :wikitext(Abbreviation.make( + Logic.isEmpty(game.length) and ('Game ' .. gameIndex) or game.length, + Logic.isEmpty(game.length) and ('Game ' .. gameIndex .. ' picks') or 'Match Length' + )) + ) + row:addElement(CustomMatchSummary._createCheckMark(game.winner, 2)) + row:addElement(makeCharacterDisplay(2)) + + if Logic.isNotEmpty(game.comment) then + row:addElement(MatchSummary.Break():create()) + row:addElement(mw.html.create('div'):css('margin', 'auto'):wikitext(game.comment)) + end + + return row +end + +---@param winner integer|string +---@param opponentIndex integer +---@return Html +function CustomMatchSummary._createCheckMark(winner, opponentIndex) + return mw.html.create('div') + :addClass('brkts-popup-spaced') + :css('line-height', '17px') + :css('margin-left', '1%') + :css('margin-right', '1%') + :wikitext( + winner == opponentIndex and ICONS.winner + or winner == 0 and ICONS.draw + or Logic.isNotEmpty(winner) and ICONS.loss + or ICONS.empty + ) +end + +---@param characters {name: string, active: boolean}[]? +---@param side string? +---@param reverse boolean? +---@return Html +function CustomMatchSummary._createCharacterDisplay(characters, side, reverse) + local wrapper = mw.html.create('div') + :addClass('brkts-popup-body-element-thumbs') + :addClass('brkts-popup-body-element-thumbs-' .. (reverse and 'right' or 'left')) + + local function makeCharacterIcon(character) + return CharacterIcon.Icon{ + character = character, + size = SIZE_HERO, + } + end + + local function characterDisplay(character, showName) + local display = mw.html.create('div') + :addClass('brkts-popup-side-color-' .. side) + :addClass('brkts-popup-side-hero') + :addClass('brkts-popup-side-hero-hover') + if not showName then + display:node(makeCharacterIcon(character)) + return display + end + if reverse then + display:wikitext(character):wikitext(' '):wikitext(makeCharacterIcon(character)) + else + display:node(makeCharacterIcon(character)):wikitext(' '):wikitext(character) + end + return display + end + + local characterDisplays = Array.map(characters or {}, function (character) + return characterDisplay(character, #characters == 1) + end) + + if reverse then + characterDisplays = Array.reverse(characterDisplays) + end + + Array.forEach(characterDisplays, FnUtil.curry(wrapper.node, wrapper)) + + return wrapper +end + +return CustomMatchSummary From dad26d47373da214c384902437f02d4a4170ee71 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Mon, 26 Aug 2024 17:32:59 +0200 Subject: [PATCH 2/6] from review --- .../wikis/deadlock/get_match_group_copy_paste_wiki.lua | 5 ++--- components/match2/wikis/deadlock/match_summary.lua | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua index 831150595e9..07a2a59ba17 100644 --- a/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua +++ b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua @@ -23,6 +23,7 @@ function WikiCopyPaste.getMatchCode(bestof, mode, index, opponents, args) local lines = Array.extend( '{{Match', + '|bestof=' .. (bestof ~= 0 and bestof or ''), Logic.readBool(args.needsWinner) and INDENT .. '|winner=' or nil, Array.map(Array.range(1, opponents), function(opponentIndex) return INDENT .. '|opponent' .. opponentIndex .. '=' .. WikiCopyPaste.getOpponent(mode, showScore) @@ -32,9 +33,7 @@ function WikiCopyPaste.getMatchCode(bestof, mode, index, opponents, args) INDENT .. '|finished=', INDENT .. '|twitch=|youtube=' } or nil, - Array.map(Array.range(1, bestof), function(mapIndex) - return WikiCopyPaste._getMapCode(mapIndex) - end), + Array.map(Array.range(1, bestof), WikiCopyPaste._getMapCode), '}}' ) diff --git a/components/match2/wikis/deadlock/match_summary.lua b/components/match2/wikis/deadlock/match_summary.lua index 8e91258268e..978f5870115 100644 --- a/components/match2/wikis/deadlock/match_summary.lua +++ b/components/match2/wikis/deadlock/match_summary.lua @@ -34,13 +34,6 @@ function CustomMatchSummary.getByMatchId(args) return MatchSummary.defaultGetByMatchId(CustomMatchSummary, args, {width = '400px', teamStyle = 'bracket'}) end ----@param match MatchGroupUtilMatch ----@param footer MatchSummaryFooter ----@return MatchSummaryFooter -function CustomMatchSummary.addToFooter(match, footer) - return MatchSummary.addVodsToFooter(match, footer) -end - ---@param match MatchGroupUtilMatch ---@return MatchSummaryBody function CustomMatchSummary.createBody(match) From 0d9d69dd90539250cb739f8488933275146b0e3d Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Tue, 27 Aug 2024 13:20:39 +0200 Subject: [PATCH 3/6] shortern down the copy paste --- .../deadlock/get_match_group_copy_paste_wiki.lua | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua index 07a2a59ba17..484ce35e0d7 100644 --- a/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua +++ b/components/match2/wikis/deadlock/get_match_group_copy_paste_wiki.lua @@ -22,17 +22,12 @@ function WikiCopyPaste.getMatchCode(bestof, mode, index, opponents, args) local showScore = Logic.nilOr(Logic.readBoolOrNil, bestof == 0) local lines = Array.extend( - '{{Match', - '|bestof=' .. (bestof ~= 0 and bestof or ''), - Logic.readBool(args.needsWinner) and INDENT .. '|winner=' or nil, + '{{Match|bestof=' .. (bestof ~= 0 and bestof or ''), Array.map(Array.range(1, opponents), function(opponentIndex) return INDENT .. '|opponent' .. opponentIndex .. '=' .. WikiCopyPaste.getOpponent(mode, showScore) end), - Logic.readBool(args.hasDate) and { - INDENT .. '|date=', - INDENT .. '|finished=', - INDENT .. '|twitch=|youtube=' - } or nil, + INDENT .. '|date=|finished=', + INDENT .. '|twitch=|youtube=|vod=', Array.map(Array.range(1, bestof), WikiCopyPaste._getMapCode), '}}' ) @@ -45,9 +40,8 @@ end function WikiCopyPaste._getMapCode(mapIndex) return table.concat(Array.extend( INDENT .. '|map' .. mapIndex .. '={{Map|length=|winner=|vod=', - INDENT .. INDENT .. '|team1side=', + INDENT .. INDENT .. '|team1side=|team2side=', INDENT .. INDENT .. '|t1h1=|t1h2=|t1h3=|t1h4=|t1h5=|t1h6=', - INDENT .. INDENT .. '|team2side=', INDENT .. INDENT .. '|t2h1=|t2h2=|t2h3=|t2h4=|t2h5=|t2h6=', INDENT .. '}}' ), '\n') From 8eaf4a3f33d38d321c9da10cbcb9cd9ef0a9ece8 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Tue, 27 Aug 2024 14:05:30 +0200 Subject: [PATCH 4/6] update m2 status --- standard/info/wikis/deadlock/info.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/info/wikis/deadlock/info.lua b/standard/info/wikis/deadlock/info.lua index 00cda98d3ef..7b7fc8c7c0f 100644 --- a/standard/info/wikis/deadlock/info.lua +++ b/standard/info/wikis/deadlock/info.lua @@ -33,7 +33,7 @@ return { allowManual = false, }, match2 = { - status = 0, + status = 2, }, }, defaultRoundPrecision = 0, From 9e7aef3c995f909e4095847d46cdef9326a9f908 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Tue, 27 Aug 2024 14:20:24 +0200 Subject: [PATCH 5/6] hero icon tweaks --- components/match2/wikis/deadlock/match_summary.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/match2/wikis/deadlock/match_summary.lua b/components/match2/wikis/deadlock/match_summary.lua index 978f5870115..f715bd73bee 100644 --- a/components/match2/wikis/deadlock/match_summary.lua +++ b/components/match2/wikis/deadlock/match_summary.lua @@ -19,7 +19,7 @@ local Table = require('Module:Table') local DisplayHelper = Lua.import('Module:MatchGroup/Display/Helper') local MatchSummary = Lua.import('Module:MatchSummary/Base') -local SIZE_HERO = '57x32px' +local SIZE_HERO = '48x48px' local ICONS = { winner = Icon.makeIcon{iconName = 'winner', color = 'forest-green-text', size = 'initial'}, loss = Icon.makeIcon{iconName = 'loss', color = 'cinnabar-text', size = 'initial'}, @@ -125,6 +125,7 @@ function CustomMatchSummary._createCharacterDisplay(characters, side, reverse) local wrapper = mw.html.create('div') :addClass('brkts-popup-body-element-thumbs') :addClass('brkts-popup-body-element-thumbs-' .. (reverse and 'right' or 'left')) + :addClass('brkts-champion-icon') local function makeCharacterIcon(character) return CharacterIcon.Icon{ @@ -134,10 +135,7 @@ function CustomMatchSummary._createCharacterDisplay(characters, side, reverse) end local function characterDisplay(character, showName) - local display = mw.html.create('div') - :addClass('brkts-popup-side-color-' .. side) - :addClass('brkts-popup-side-hero') - :addClass('brkts-popup-side-hero-hover') + local display = mw.html.create('div'):addClass('brkts-popup-side-color-' .. side) if not showName then display:node(makeCharacterIcon(character)) return display From 6c5d16734864aea207005edf181295fbb96c593e Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 28 Aug 2024 13:27:31 +0200 Subject: [PATCH 6/6] remove side colors --- components/match2/wikis/deadlock/match_summary.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/match2/wikis/deadlock/match_summary.lua b/components/match2/wikis/deadlock/match_summary.lua index f715bd73bee..c5b744c88dd 100644 --- a/components/match2/wikis/deadlock/match_summary.lua +++ b/components/match2/wikis/deadlock/match_summary.lua @@ -135,7 +135,7 @@ function CustomMatchSummary._createCharacterDisplay(characters, side, reverse) end local function characterDisplay(character, showName) - local display = mw.html.create('div'):addClass('brkts-popup-side-color-' .. side) + local display = mw.html.create('div') if not showName then display:node(makeCharacterIcon(character)) return display