Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(match2): deadlock setup #4652

Merged
merged 6 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
-- @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|bestof=' .. (bestof ~= 0 and bestof or ''),
Array.map(Array.range(1, opponents), function(opponentIndex)
return INDENT .. '|opponent' .. opponentIndex .. '=' .. WikiCopyPaste.getOpponent(mode, showScore)
end),
INDENT .. '|date=|finished=',
INDENT .. '|twitch=|youtube=|vod=',
Array.map(Array.range(1, bestof), WikiCopyPaste._getMapCode),
'}}'
)

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=|team2side=',
INDENT .. INDENT .. '|t1h1=|t1h2=|t1h3=|t1h4=|t1h5=|t1h6=',
INDENT .. INDENT .. '|t2h1=|t2h2=|t2h3=|t2h4=|t2h5=|t2h6=',
INDENT .. '}}'
), '\n')
end

return WikiCopyPaste
181 changes: 181 additions & 0 deletions components/match2/wikis/deadlock/match_group_input_custom.lua
Original file line number Diff line number Diff line change
@@ -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
Rathoz marked this conversation as resolved.
Show resolved Hide resolved

---@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
166 changes: 166 additions & 0 deletions components/match2/wikis/deadlock/match_summary.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
-- @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
---@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
Loading
Loading