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): support hearthstone #4518

Merged
merged 27 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
21a41b8
Create Match Summary for hearthstone
Kanopedia Aug 12, 2024
220dd9d
Create Match Group Input for Hearthstone
Kanopedia Aug 12, 2024
ed81878
Create get_match_group_copy_paste_wiki.lua
Kanopedia Aug 12, 2024
dbd805d
Update match_group_input_custom.lua
Kanopedia Aug 12, 2024
256a7ba
Update match_group_input_custom.lua
Kanopedia Aug 12, 2024
1dc5cd5
Update match_group_input_custom.lua
Kanopedia Aug 12, 2024
33abedf
Update match_summary.lua
Kanopedia Aug 12, 2024
5c670bb
Update match_summary.lua
Kanopedia Aug 12, 2024
d1cd7d7
Update match_summary.lua
Kanopedia Aug 12, 2024
48afbc5
as per review
hjpalpha Sep 3, 2024
5d73384
ms: fix anno
hjpalpha Sep 3, 2024
7277443
fix(ms): do not apply css to potential nil
hjpalpha Sep 3, 2024
06d02b5
linter
hjpalpha Sep 3, 2024
69c2dcd
input refactor
hjpalpha Sep 3, 2024
6475574
adjust copy paste (add team support)
hjpalpha Sep 3, 2024
4d46a28
store chars in extradata too (to be able to condition on them)
hjpalpha Sep 3, 2024
4289d84
kick unsued cars and requires
hjpalpha Sep 3, 2024
0e8bcd5
and another one
hjpalpha Sep 3, 2024
02315fa
map function -> identity
hjpalpha Sep 3, 2024
f9937b1
fix
hjpalpha Sep 3, 2024
762eb51
#4650
hjpalpha Sep 10, 2024
6bcb14f
update with changes from #4839
Rathoz Oct 10, 2024
79fe987
change from #4842
Rathoz Oct 10, 2024
8cb2744
Update Hearthstone Info M2 status (#4844)
Kanopedia Oct 10, 2024
4af5add
Create match_legacy for Hearthstone (#4846)
Kanopedia Oct 10, 2024
73498d8
change from #4841
Rathoz Oct 10, 2024
da10edc
aano wanring
Rathoz Oct 10, 2024
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,73 @@
---
-- @Liquipedia
-- wiki=hearthstone
-- 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')
local OpponentLibrary = Lua.import('Module:OpponentLibraries')
local Opponent = OpponentLibrary.Opponent

---WikiSpecific Code for MatchList and Bracket Code Generators
---@class HearthstoneMatchCopyPaste: Match2CopyPasteBase
local WikiCopyPaste = Class.new(BaseCopyPaste)

local INDENT = WikiCopyPaste.Indent

---returns the Code for a Match, depending on the input
---@param bestof integer
---@param mode string
---@param index integer
---@param opponents integer
---@param args table
---@return string
function WikiCopyPaste.getMatchCode(bestof, mode, index, opponents, args)
local showScore = Logic.nilOr(Logic.readBool(args.score), true)

local lines = Array.extend(
'{{Match|bestof=' .. bestof,
INDENT .. '|date=',
INDENT .. '|twitch=|vod=',
Array.map(Array.range(1, opponents), function(opponentIndex)
return INDENT .. '|opponent' .. opponentIndex .. '=' .. WikiCopyPaste.getOpponent(mode, showScore)
end),
Array.map(Array.range(1, bestof), function(mapIndex)
return INDENT .. '|map' .. mapIndex .. WikiCopyPaste._getMap(mode, opponents)
end),
'}}'
)

return table.concat(lines, '\n')
end

--subfunction used to generate code for the Map template, depending on the type of opponent
---@param mode string
---@param opponents integer
---@return string
function WikiCopyPaste._getMap(mode, opponents)
if mode == Opponent.team then
return '={{Map|o1p1=|o2p1=|o1p1char=|o2p1char=|winner=}}'
elseif mode == Opponent.literal then
return '={{Map|winner=}}'
end

local parts = Array.extend({},
Array.map(Array.range(1, opponents), function(opponentIndex)
return table.concat(Array.map(Array.range(1, Opponent.partySize(mode) --[[@as integer]]), function(playerIndex)
return '|o' .. opponentIndex .. 'p' .. playerIndex .. '='
end))
end),
'}}'
)

return table.concat(parts)
end

return WikiCopyPaste
261 changes: 261 additions & 0 deletions components/match2/wikis/hearthstone/match_group_input_custom.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
---
hjpalpha marked this conversation as resolved.
Show resolved Hide resolved
-- @Liquipedia
-- wiki=hearthstone
-- page=Module:MatchGroup/Input/Custom
--
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
--

local Array = require('Module:Array')
local CharacterStandardization = mw.loadData('Module:CharacterStandardization')
local FnUtil = require('Module:FnUtil')
local Logic = require('Module:Logic')
local Lua = require('Module:Lua')
local Operator = require('Module:Operator')
local String = require('Module:StringUtils')
local Table = require('Module:Table')
local Variables = require('Module:Variables')

local MatchGroupInputUtil = Lua.import('Module:MatchGroup/Input/Util')
local OpponentLibraries = require('Module:OpponentLibraries')
local Opponent = OpponentLibraries.Opponent
local Streams = Lua.import('Module:Links/Stream')

local OPPONENT_CONFIG = {
resolveRedirect = true,
pagifyTeamNames = true,
pagifyPlayerNames = true,
}
local TBD = 'TBD'

local CustomMatchGroupInput = {}
local MatchFunctions = {}
local MapFunctions = {}

---@param match table
---@param options table?
---@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)

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)
Array.forEach(opponents, function(opponent, opponentIndex)
opponent.placement = MatchGroupInputUtil.placementFromWinner(match.resulttype, match.winner, opponentIndex)
end)
end

match.mode = Variables.varDefault('tournament_mode', 'singles')
Table.mergeInto(match, MatchGroupInputUtil.getTournamentContext(match))

match.stream = Streams.processStreams(match)

match.games = games
match.opponents = opponents

return match
end

---@param maps table[]
---@return fun(opponentIndex: integer): integer?
function MatchFunctions.calculateMatchScore(maps)
return function(opponentIndex)
return MatchGroupInputUtil.computeMatchScoreFromMapWinners(maps, opponentIndex)
end
end

---@param bestofInput string|integer?
---@return integer?
function MatchFunctions.getBestOf(bestofInput)
return tonumber(bestofInput)
end

---@param match table
---@param opponents table[]
---@return table[]
function MatchFunctions.extractMaps(match, opponents)
local maps = {}
for mapKey, map in Table.iter.pairsByPrefix(match, 'map', {requireIndex = true}) do
local finishedInput = map.finished --[[@as string?]]
local winnerInput = map.winner --[[@as string?]]

if String.isNotEmpty(map.map) and string.upper(map.map) ~= TBD then
map.map = mw.ext.TeamLiquidIntegration.resolve_redirect(map.map)
end

map.finished = MatchGroupInputUtil.mapIsFinished(map)

local opponentInfo = Array.map(Array.range(1, #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 then
map.resulttype = MatchGroupInputUtil.getResultType(winnerInput, finishedInput, opponentInfo)
map.walkover = MatchGroupInputUtil.getWalkover(map.resulttype, opponentInfo)
map.winner = MatchGroupInputUtil.getWinner(map.resulttype, winnerInput, opponentInfo)
end

map.extradata = MapFunctions.getExtradata(map, opponents)

map.participants = MapFunctions.getParticipants(map, opponents)

table.insert(maps, map)
match[mapKey] = nil
end

return maps
end

---@param mapInput table
---@param opponents table[]
---@return table
function MapFunctions.getExtradata(mapInput, opponents)
local extradata = {comment = mapInput.comment}

Array.forEach(opponents, function(opponent, opponentIndex)
local prefix = 'o' .. opponentIndex .. 'p'
local chars = Array.mapIndexes(function(charIndex)
return Logic.nilIfEmpty(mapInput[prefix .. charIndex .. 'char']) or Logic.nilIfEmpty(mapInput[prefix .. charIndex])
end)
Array.forEach(chars, function(char, charIndex)
extradata[prefix .. charIndex] = MapFunctions.readCharacter(char)
end)
end)

return extradata
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

---@param mapInput table
---@param opponents table[]
---@return table<string, {character: string?, player: string}>
function MapFunctions.getParticipants(mapInput, opponents)
local participants = {}
Array.forEach(opponents, function(opponent, opponentIndex)
if opponent.type == Opponent.literal then
return
elseif opponent.type == Opponent.team then
Table.mergeInto(participants, MapFunctions.getTeamParticipants(mapInput, opponent, opponentIndex))
return
end
Table.mergeInto(participants, MapFunctions.getPartyParticipants(mapInput, opponent, opponentIndex))
end)

return participants
end

---@param mapInput table
---@param opponent table
---@param opponentIndex integer
---@return table<string, {character: string?, player: string}>
function MapFunctions.getTeamParticipants(mapInput, opponent, opponentIndex)
local players = Array.mapIndexes(function(playerIndex)
return Logic.nilIfEmpty(mapInput['o' .. opponentIndex .. 'p' .. playerIndex])
end)

local participants, unattachedParticipants = MatchGroupInputUtil.parseParticipants(
opponent.match2players,
players,
function(playerIndex)
local prefix = 'o' .. opponentIndex .. 'p' .. playerIndex
return {
name = mapInput[prefix],
link = Logic.nilIfEmpty(mapInput[prefix .. 'link']),
}
end,
function(playerIndex, playerIdData, playerInputData)
local prefix = 'o' .. opponentIndex .. 'p' .. playerIndex
return {
player = playerIdData.name or playerInputData.link,
character = MapFunctions.readCharacter(Logic.nilIfEmpty(mapInput[prefix .. 'char']).character),
}
end
)

Array.forEach(unattachedParticipants, function(participant)
table.insert(opponent.match2players, {
name = participant.player,
displayname = participant.player,
})
participants[#opponent.match2players] = participant
end)

return Table.map(participants, MatchGroupInputUtil.prefixPartcipants(opponentIndex))
end

---@param mapInput table
---@param opponent table
---@param opponentIndex integer
---@return table<string, {character: string?, player: string}>
function MapFunctions.getPartyParticipants(mapInput, opponent, opponentIndex)
local players = opponent.match2players

local prefix = 'o' .. opponentIndex .. 'p'

local participants = {}

Array.forEach(players, function(player, playerIndex)
participants[opponentIndex .. '_' .. playerIndex] = {
character = MapFunctions.readCharacter(mapInput[prefix .. playerIndex]),
player = player.name,
}
end)

return participants
end

---@param input string?
---@return string?
function MapFunctions.readCharacter(input)
local getCharacterName = FnUtil.curry(MatchGroupInputUtil.getCharacterName, CharacterStandardization)

return getCharacterName(input)
end

return CustomMatchGroupInput
Loading
Loading