Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
30 changes: 25 additions & 5 deletions lua/wikis/commons/StageWinningsCalculation.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ local ColumnName = Condition.ColumnName
local StageWinningsCalculation = {}

---@param props {matchGroupsSpecProps: table<string, string>, startDate: integer?, endDate: integer?, mode: string,
---startValue: number, valuePerWin: number, valueByScore: table<string, number>?}
---startValue: number, valuePerWin: number, valueByScore: table<string, number>?,
---pointsStart: number, pointsPerWin: number, pointsByScore: table<string, number>?,
---points2Start: number, points2PerWin: number, points2ByScore: table<string, number>?, hideWinnings: boolean}
---@return {opponent: standardOpponent, matchWins: integer, matchLosses: integer, gameWins: integer,
---gameLosses: integer, winnings: number, scoreDetails: table<string, integer>}[]
---gameLosses: integer, winnings: number, scoreDetails: table<string, integer>, points: number, points2: number}[]
function StageWinningsCalculation.run(props)
local matches = mw.ext.LiquipediaDB.lpdb('match2', {
conditions = StageWinningsCalculation._buildConditions(props),
Expand Down Expand Up @@ -52,6 +54,8 @@ function StageWinningsCalculation.run(props)
gameWins = 0,
gameLosses = 0,
winnings = 0,
points = 0,
points2 = 0,
}
end)

Expand Down Expand Up @@ -85,22 +89,38 @@ function StageWinningsCalculation.run(props)
Array.forEach(opponents, function(opponent)
if props.mode == 'matchWins' then
opponent.winnings = props.startValue + opponent.matchWins * props.valuePerWin
opponent.points = props.pointsStart + opponent.matchWins * props.pointsPerWin
opponent.points2 = props.points2Start + opponent.matchWins * props.points2PerWin
return
elseif props.mode == 'gameWins' then
opponent.winnings = props.startValue + opponent.gameWins * props.valuePerWin
opponent.points = props.pointsStart + opponent.gameWins * props.pointsPerWin
opponent.points2 = props.points2Start + opponent.gameWins * props.points2PerWin
return
end
-- case: props.mode == 'scores'
local winnings = props.startValue
local points = props.pointsStart
local points2 = props.points2Start
for score, count in pairs(opponent.scoreDetails) do
winnings = winnings + (props.valueByScore[score] or 0) * count
points = points + (props.pointsByScore[score] or 0) * count
points2 = points2 + (props.points2ByScore[score] or 0) * count
end
opponent.winnings = winnings
opponent.points = points
opponent.points2 = points2
end)

Array.sortInPlaceBy(opponents, function(opponent)
return {- opponent.winnings, - opponent.matchWins, - opponent.gameWins, Opponent.toName(opponent)}
end)
if props.hideWinnings then
Array.sortInPlaceBy(opponents, function(opponent)
return {- opponent.points, - opponent.points, - opponent.matchWins, - opponent.gameWins, Opponent.toName(opponent)}
end)
else
Array.sortInPlaceBy(opponents, function(opponent)
return {- opponent.winnings, - opponent.matchWins, - opponent.gameWins, Opponent.toName(opponent)}
end)
end

return opponents

Expand Down
135 changes: 106 additions & 29 deletions lua/wikis/commons/Widget/StageWinnings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,62 @@ local Class = Lua.import('Module:Class')
local Currency = Lua.import('Module:Currency')
local DateExt = Lua.import('Module:Date/Ext')
local FnUtil = Lua.import('Module:FnUtil')
local LeagueIcon = Lua.import('Module:LeagueIcon')
local Logic = Lua.import('Module:Logic')
local MatchGroupInputUtil = Lua.import('Module:MatchGroup/Input/Util')
local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom')
local Points = Lua.import('Module:Points/data', {loadData = true})
local StageWinningsCalculation = Lua.import('Module:StageWinningsCalculation')
local String = Lua.import('Module:StringUtils')
local Table = Lua.import('Module:Table')
local Variables = Lua.import('Module:Variables')

local Link = Lua.import('Module:Widget/Basic/Link')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local TableWidgets = Lua.import('Module:Widget/Table2/All')
local Widget = Lua.import('Module:Widget')
local WidgetUtil = Lua.import('Module:Widget/Util')

local BASE_CURRENCY = 'USD'
local NON_BREAKING_SPACE = '&nbsp;'

---@class StageWinningProps
---@field tournaments string
---@field ids string?
---@field tournament1 string?
---@field tournament2 string?
---@field tournament3 string?
---@field matchGroupId1 string?
---@field matchGroupId2 string?
---@field matchGroupId3 string?
---@field sdate string|number|osdate|osdateparam?
---@field edate string|number|osdate|osdateparam?
---@field prizeMode 'matchWins'|'gameWins'|'scores'
---@field points string?
---@field points2 string?
---@field valueStart number?
---@field valuePerWin number?
---@field pointsStart number?
---@field pointsPerWin number?
---@field points2Start number?
---@field points2PerWin number?
---@field n-m number? # n amd m integers
---@field n-m_points number? # n amd m integers
---@field n-m_points2 number? # n amd m integers
---@field localcurrency string?
---@field width integer?
---@field cutafter integer?
---@field title string?
---@field precision integer?
---@field autoexchange boolean
---@field showMatchWL boolean
---@field showGameWL boolean
---@field showScore boolean
---@field showMatchWL boolean?
---@field showGameWL boolean?
---@field showScore boolean?
---@field hideWinnings boolean?

---@class StageWinnings: Widget
---@operator call(table): StageWinnings
---@field props StageWinningProps
---@field points {title: string, icon: string?, iconDark: string?, link: string?, titleLong: string?}?
---@field points2 {title: string, icon: string?, iconDark: string?, link: string?, titleLong: string?}?
local StageWinnings = Class.new(Widget)
StageWinnings.defaultProps = {
tournaments = mw.title.getCurrentTitle().text,
delimiter = ',',
autoexchange = true,
prizeMode = 'matchWins',
title = 'Group Stage Winnings'
Expand All @@ -65,21 +80,27 @@ function StageWinnings:render()
local startDate = DateExt.readTimestamp(props.sdate)
local endDate = DateExt.readTimestamp(props.edate)

local valueByScore = Table.filterByKey(props, function(key)
if key:match('^%d+%-%d+$') ~= nil then
return true
end
local keyParts = Array.parseCommaSeparatedString(key, '-')
return #keyParts == 2 and
Array.all(keyParts, function(keyPart) return Table.includes(MatchGroupInputUtil.STATUS, keyPart) end)
end)
valueByScore = Table.map(valueByScore, function(key, value)
return key, tonumber(value)
end)
local getValuesByScore = function(postFix)
local valueByScore = Table.filterByKey(props, function(key)
if key:match('^%d+%-%d+' .. postFix .. '$') ~= nil then
return true
end
local keyParts = Array.parseCommaSeparatedString((key:gsub(postFix, '')), '-')
return #keyParts == 2 and
Array.all(keyParts, function(keyPart) return Table.includes(MatchGroupInputUtil.STATUS, keyPart) end)
end)
return Table.map(valueByScore, function(key, value)
return key, tonumber(value)
end)
end

local valueByScore = getValuesByScore('')
local pointsByScore = getValuesByScore('_points')
local points2ByScore = getValuesByScore('_points2')

assert(props.prizeMode == 'matchWins' or props.prizeMode == 'gameWins' or props.prizeMode == 'scores',
'Invalid prizeMode input')
assert(props.prizeMode ~= 'scores' or Logic.isNotEmpty(valueByScore),
assert(props.prizeMode ~= 'scores' or Logic.isNotEmpty(valueByScore) or Logic.isNotEmpty(pointsByScore),
'No values per scores defined')

local opponentList = StageWinningsCalculation.run{
Expand All @@ -90,20 +111,41 @@ function StageWinnings:render()
endDate = endDate,
mode = props.prizeMode,
valueByScore = valueByScore,
pointsByScore = pointsByScore,
points2ByScore = points2ByScore,
startValue = tonumber(props.valueStart) or 0,
pointsStart = tonumber(props.pointsStart) or 0,
points2Start = tonumber(props.points2Start) or 0,
valuePerWin = tonumber(props.valuePerWin) or 0,
pointsPerWin = tonumber(props.pointsPerWin) or 0,
points2PerWin = tonumber(props.points2PerWin) or 0,
hideWinnings = Logic.readBool(props.hideWinnings),
}

if Logic.isNotEmpty(props.localcurrency) and Logic.readBool(props.autoexchange) then
Currency.display(props.localcurrency, nil, {setVariables = true})
self.currencyRate = Currency.getExchangeRate{
currency = props.localcurrency,
currencyRate = Variables.varDefault('exchangerate_' .. props.localcurrency:upper()),
date = DateExt.toYmdInUtc(endDate or DateExt.getContextualDateOrNow()),
setVariables = false
}
end

---@param prefix string
---@return {title: string, icon: string?, iconDark: string?, link: string?, titleLong: string?}?
local parsePoints = function(prefix)
if Logic.isEmpty(props[prefix]) then
return
end

local pointsData = Table.copy(Points[props[prefix]] or {})
pointsData.title = pointsData.title or props[prefix]
pointsData.link = props[prefix .. 'link']

return pointsData
end
self.points = parsePoints('points')
self.points2 = parsePoints('points2')

return TableWidgets.Table{
caption = props.title,
tableClasses = {'prizepooltable', 'collapsed'},
Expand All @@ -118,7 +160,11 @@ function StageWinnings:render()
(Logic.readBool(props.showGameWL) or props.prizeMode == 'gameWins') and {align = 'center'} or nil,
Logic.readBool(props.showScore) and {align = 'left'} or nil,
Logic.isNotEmpty(props.localcurrency) and {align = 'right'} or nil,
(Logic.readBool(props.autoexchange) or Logic.isEmpty(props.localcurrency)) and {align = 'right'} or nil
(Logic.readBool(props.autoexchange) or Logic.isEmpty(props.localcurrency))
and (not Logic.readBool(props.hideWinnings)) and {align = 'right'}
or nil,
Logic.isNotEmpty(self.points) and {align = 'right'} or nil,
Logic.isNotEmpty(self.points2) and {align = 'right'} or nil
),
children = {
self:_headerRow(),
Expand All @@ -143,14 +189,17 @@ function StageWinnings:_headerRow()
Logic.isNotEmpty(props.localcurrency)
and TableWidgets.CellHeader{children = Currency.display(props.localcurrency)} or nil,
(Logic.readBool(props.autoexchange) or Logic.isEmpty(props.localcurrency))
and TableWidgets.CellHeader{children = Currency.display(BASE_CURRENCY)} or nil
and (not Logic.readBool(props.hideWinnings))
and TableWidgets.CellHeader{children = Currency.display(BASE_CURRENCY)} or nil,
self:_pointsHeader(self.points),
self:_pointsHeader(self.points2)
)}
}}
end

---@private
---@param data {opponent: standardOpponent, matchWins: integer, matchLosses: integer, gameWins: integer,
---gameLosses: integer, winnings: number, scoreDetails: table<string, integer>}
---gameLosses: integer, winnings: number, points: number, points2: number, scoreDetails: table<string, integer>}
---@return Widget
function StageWinnings:_row(data)
local props = self.props
Expand Down Expand Up @@ -189,12 +238,19 @@ function StageWinnings:_row(data)
currencyDisplayConfig
),
} or nil,
(Logic.readBool(props.autoexchange) or Logic.isEmpty(props.localcurrency)) and TableWidgets.Cell{
children = Currency.display(
(Logic.readBool(props.autoexchange) or Logic.isEmpty(props.localcurrency))
and (not Logic.readBool(props.hideWinnings)) and TableWidgets.Cell{children = Currency.display(
BASE_CURRENCY,
data.winnings * (self.currencyRate or 1),
currencyDisplayConfig
),
)} or nil,
Logic.isNotEmpty(self.points) and TableWidgets.Cell{
children = Currency.formatMoney(data.points, 2, false, true),
['data-sort-value'] = data.points,
} or nil,
Logic.isNotEmpty(self.points2) and TableWidgets.Cell{
children = Currency.formatMoney(data.points2, 2, false, true),
['data-sort-value'] = data.points2,
} or nil
),
}
Expand Down Expand Up @@ -225,4 +281,25 @@ function StageWinnings._detailedScores(scoresTable)
)
end

---@private
---@param data {title: string, icon: string?, iconDark: string?, link: string?, titleLong: string?}?
---@return Widget?
function StageWinnings:_pointsHeader(data)
if not data then
return
end

local titleText = Logic.isNotEmpty(data.titleLong) and HtmlWidgets.Abbr{
children = data.title, title = data.titleLong
} or data.title

return TableWidgets.CellHeader{children = WidgetUtil.collect(
Logic.isNotEmpty(data.icon) and {
LeagueIcon.display{link = data.link, icon = data.icon, iconDark = data.iconDark, name = data.title},
NON_BREAKING_SPACE,
} or nil,
Logic.isNotEmpty(data.link) and Link{link = data.link, children = titleText} or titleText
)}
end

return StageWinnings
Loading