From 406707d670fecaa53783a972c36c40a2fcc3050e Mon Sep 17 00:00:00 2001 From: mischiefcs Date: Thu, 19 Mar 2026 18:18:00 +0000 Subject: [PATCH 1/4] initial draft --- lua/definitions/liquipedia_db.lua | 1 + lua/wikis/commons/Mock/Lpdb.lua | 1 + .../commons/PrizePool/Award/Placement.lua | 5 +- lua/wikis/commons/PrizePool/Base.lua | 25 + lua/wikis/commons/PrizePool/Placement.lua | 3 + .../commons/TeamParticipants/Repository.lua | 7 + .../counterstrike/Infobox/League/Custom.lua | 3 + .../counterstrike/MainPageLayout/data.lua | 19 +- lua/wikis/counterstrike/VRSStandings.lua | 445 ++++++++++++++++++ 9 files changed, 506 insertions(+), 3 deletions(-) create mode 100644 lua/wikis/counterstrike/VRSStandings.lua diff --git a/lua/definitions/liquipedia_db.lua b/lua/definitions/liquipedia_db.lua index f62238aef37..9b332ec9e00 100644 --- a/lua/definitions/liquipedia_db.lua +++ b/lua/definitions/liquipedia_db.lua @@ -39,6 +39,7 @@ local lpdb = {} ---@field placement string ---@field prizemoney number ---@field individualprizemoney number +---@field playershare number ---@field prizepoolindex integer ---@field weight number ---@field mode string diff --git a/lua/wikis/commons/Mock/Lpdb.lua b/lua/wikis/commons/Mock/Lpdb.lua index 92f3bf8b953..b04a628ba09 100644 --- a/lua/wikis/commons/Mock/Lpdb.lua +++ b/lua/wikis/commons/Mock/Lpdb.lua @@ -62,6 +62,7 @@ dbStructure.placement = { placement = 'number|string|nil', prizemoney = 'number?', individualprizemoney = 'number?', + playershare = 'number?', prizepoolindex = 'number?', weight = 'number?', mode = 'string?', diff --git a/lua/wikis/commons/PrizePool/Award/Placement.lua b/lua/wikis/commons/PrizePool/Award/Placement.lua index b64c29a90e2..41917ecc403 100644 --- a/lua/wikis/commons/PrizePool/Award/Placement.lua +++ b/lua/wikis/commons/PrizePool/Award/Placement.lua @@ -18,6 +18,7 @@ local _tbd_index = 0 local PRIZE_TYPE_BASE_CURRENCY = 'BASE_CURRENCY' local PRIZE_TYPE_POINTS = 'POINTS' +local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' --- An AwardPlacement is a set of opponents who all share the same award in the tournament. --- Its input is generally a table created by `Template:Slot`. @@ -75,10 +76,12 @@ function AwardPlacement:_getLpdbData(...) local prizeMoney = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_BASE_CURRENCY .. 1)) or 0 local pointsReward = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 1) local pointsReward2 = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 2) + local playerShare = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_PLAYER_SHARE .. 1)) local lpdbData = { date = opponent.date, prizemoney = prizeMoney, - individualprizemoney = Opponent.typeIsParty(opponentType) and (prizeMoney / Opponent.partySize(opponentType)) or 0, + individualprizemoney = Opponent.typeIsParty(opponentType) and ((playerShare or prizeMoney) / Opponent.partySize(opponentType)) or 0, + playerShare = not Opponent.typeIsParty(opponentType) and playerShare or nil, mode = 'award_individual', weight = 0, extradata = { diff --git a/lua/wikis/commons/PrizePool/Base.lua b/lua/wikis/commons/PrizePool/Base.lua index 143635d94f4..a0b68179783 100644 --- a/lua/wikis/commons/PrizePool/Base.lua +++ b/lua/wikis/commons/PrizePool/Base.lua @@ -63,6 +63,7 @@ local PRIZE_TYPE_QUALIFIES = 'QUALIFIES' local PRIZE_TYPE_POINTS = 'POINTS' local PRIZE_TYPE_PERCENTAGE = 'PERCENT' local PRIZE_TYPE_FREETEXT = 'FREETEXT' +local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' BasePrizePool.config = { showBaseCurrency = { @@ -357,6 +358,30 @@ BasePrizePool.prizeTypes = { end end, }, + [PRIZE_TYPE_PLAYER_SHARE] = { + sortOrder = 55, + + header = 'playershare', + headerParse = function (prizePool, input, context, index) + return {title = 'Player Share'} + end, + headerDisplay = function (data) + return TableCell{children = {data.title}} + end, + + row = 'playershare', + rowParse = function (placement, input, context, index) + return BasePrizePool._parseInteger(input) + end, + rowDisplay = function (headerData, data) + if data > 0 then + return TableCell{children = { + Currency.display(BASE_CURRENCY, data, + {formatValue = true, formatPrecision = headerData.roundPrecision, displayCurrencyCode = false}) + }} + end + end, + }, [PRIZE_TYPE_FREETEXT] = { sortOrder = 60, diff --git a/lua/wikis/commons/PrizePool/Placement.lua b/lua/wikis/commons/PrizePool/Placement.lua index 3e11a0935b8..ee0d92256b8 100644 --- a/lua/wikis/commons/PrizePool/Placement.lua +++ b/lua/wikis/commons/PrizePool/Placement.lua @@ -26,6 +26,7 @@ local DASH = '-' local PRIZE_TYPE_BASE_CURRENCY = 'BASE_CURRENCY' local PRIZE_TYPE_POINTS = 'POINTS' local PRIZE_TYPE_QUALIFIES = 'QUALIFIES' +local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' -- Allowed none-numeric score values. local SPECIAL_SCORES = {'W', 'FF' , 'L', 'DQ', 'D'} @@ -235,6 +236,7 @@ function Placement:_getLpdbData(...) local pointsReward = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 1) local pointsReward2 = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 2) local isQualified = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_QUALIFIES .. '1') + local playerShare = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_PLAYER_SHARE .. 1)) or 0 local lpdbData = { image = image, @@ -262,6 +264,7 @@ function Placement:_getLpdbData(...) participantteam = (opponentType == Opponent.solo and players.p1team) and Opponent.toName{template = players.p1team, type = 'team', extradata = {}} or nil, + playershare = playerShare and tostring(playerShare) or nil, }, qualified = isQualified and 1 or 0 -- TODO: We need to create additional LPDB Fields diff --git a/lua/wikis/commons/TeamParticipants/Repository.lua b/lua/wikis/commons/TeamParticipants/Repository.lua index 26a9629f4c6..79cc9ffd9b8 100644 --- a/lua/wikis/commons/TeamParticipants/Repository.lua +++ b/lua/wikis/commons/TeamParticipants/Repository.lua @@ -101,6 +101,13 @@ function TeamParticipantsRepository.save(participant) lpdbData.individualprizemoney = lpdbData.prizemoney / numberOfPlayersOnTeam end + -- Calculate individual playerShare + if lpdbData.playershare then + if activeOpponent.type ~= Opponent.team then + lpdbData.individualprizemoney = lpdbData.playershare + end + end + mw.ext.LiquipediaDB.lpdb_placement(lpdbData.objectName, Json.stringifySubTables(lpdbData)) end diff --git a/lua/wikis/counterstrike/Infobox/League/Custom.lua b/lua/wikis/counterstrike/Infobox/League/Custom.lua index 99a22eca738..2e5a3b3e2ae 100644 --- a/lua/wikis/counterstrike/Infobox/League/Custom.lua +++ b/lua/wikis/counterstrike/Infobox/League/Custom.lua @@ -87,7 +87,10 @@ local VALVE_TIERS = { ['tier 1 qualifier'] = {meta = 'Valve Tier 1 qualifier', name = 'Tier 1 Qualifier', link = 'Valve Tier 1 Events'}, ['tier 2'] = {meta = 'Valve Tier 2 event', name = 'Tier 2', link = 'Valve Tier 2 Events'}, ['tier 2 qualifier'] = {meta = 'Valve Tier 2 qualifier', name = 'Tier 2 Qualifier', link = 'Valve Tier 2 Events'}, + ['tier 2 open sign ups'] = {meta = 'Valve Tier 2 open sign-up', name = 'Tier 2 Open Sign-up', link = 'Valve Tier 2 Events'}, ['wildcard'] = {meta = 'Valve Wildcard event', name = 'Wildcard', link = 'Valve Wildcard Events'}, + ['tier 1 wildcard'] = {meta = 'Valve Tier 1 Wildcard event', name = 'Tier 1 Wildcard', link = 'Valve Wildcard Events'}, + ['tier 2 wildcard'] = {meta = 'Valve Tier 2 Wildcard event', name = 'Tier 2 Wildcard', link = 'Valve Wildcard Events'}, } local RESTRICTIONS = { diff --git a/lua/wikis/counterstrike/MainPageLayout/data.lua b/lua/wikis/counterstrike/MainPageLayout/data.lua index e3befcf3033..30401161ef8 100644 --- a/lua/wikis/counterstrike/MainPageLayout/data.lua +++ b/lua/wikis/counterstrike/MainPageLayout/data.lua @@ -18,6 +18,7 @@ local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons') local ThisDayWidgets = Lua.import('Module:Widget/MainPage/ThisDay') local TransfersList = Lua.import('Module:Widget/MainPage/TransfersList') local WantToHelp = Lua.import('Module:Widget/MainPage/WantToHelp') +local VRSStandings = Lua.import('Module:Widget/VRSStandings') local CONTENT = { @@ -74,6 +75,16 @@ local CONTENT = { padding = true, boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER, }, + vrsStandings = { + heading = 'Valve Regional Standings', + body = VRSStandings{ + shouldFetch = 1, + fetchLimit = 5, + mainpage = 1, + }, + padding = false, + boxid = 1521, + } } return { @@ -146,13 +157,17 @@ return { mobileOrder = 1, content = CONTENT.specialEvents, }, + { + mobileOrder = 3, + content = CONTENT.vrsStandings, + }, { mobileOrder = 4, - content = CONTENT.thisDay, + content = CONTENT.transfers, }, { mobileOrder = 5, - content = CONTENT.transfers, + content = CONTENT.thisDay, }, { mobileOrder = 7, diff --git a/lua/wikis/counterstrike/VRSStandings.lua b/lua/wikis/counterstrike/VRSStandings.lua new file mode 100644 index 00000000000..c051d73ceb5 --- /dev/null +++ b/lua/wikis/counterstrike/VRSStandings.lua @@ -0,0 +1,445 @@ +--- +-- @Liquipedia +-- page=Module:Widget/VRSStandings.lua +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local Array = Lua.import('Module:Array') +local Class = Lua.import('Module:Class') +local DateExt = Lua.import('Module:Date/Ext') +local FnUtil = Lua.import('Module:FnUtil') +local Json = Lua.import('Module:Json') +local Logic = Lua.import('Module:Logic') +local Lpdb = Lua.import('Module:Lpdb') +local MathUtil = Lua.import('Module:MathUtil') +local Operator = Lua.import('Module:Operator') +local Opponent = Lua.import('Module:Opponent') +local PlayerDisplay = Lua.import('Module:Player/Display') +local OpponentDisplay = Lua.import('Module:OpponentDisplay') +local Table = Lua.import('Module:Table') + +local TableWidgets = Lua.import('Module:Widget/Table2/All') +local Widget = Lua.import('Module:Widget') +local WidgetUtil = Lua.import('Module:Widget/Util') +local HtmlWidgets = Lua.import('Module:Widget/Html/All') + +local Condition = Lua.import('Module:Condition') +local BooleanOperator = Condition.BooleanOperator +local Comparator = Condition.Comparator + +local Link = Lua.import('Module:Widget/Basic/Link') +local Icon = Lua.import('Module:Icon') + + +local DATAPOINT_TYPE_LIVE = 'vrs_ranking_live' +local DATAPOINT_TYPE_MAIN = 'vrs_ranking' +local FOOTER_LINK = 'Valve_Regional_Standings' + +---@class VRSStandings: Widget +---@operator call(table): VRSStandings +---@field props table +local VRSStandings = Class.new(Widget) +VRSStandings.defaultProps = { + title = 'VRS Standings', + filterRegion = nil, + filterSubregion = nil, + filterCountry = nil, + mainpage = nil, + rankingType = 'live', +} + +---@return Widget? +function VRSStandings:render() + local standings, settings = self:_parse() + + local headerCells + if settings.filterType ~= 'none' then + headerCells = WidgetUtil.collect( + TableWidgets.CellHeader{children = 'Rank'}, + TableWidgets.CellHeader{children = 'Global Rank'}, + TableWidgets.CellHeader{children = 'Points'}, + TableWidgets.CellHeader{children = 'Team'} + ) + else + headerCells = WidgetUtil.collect( + TableWidgets.CellHeader{children = 'Rank'}, + TableWidgets.CellHeader{children = 'Points'}, + TableWidgets.CellHeader{children = 'Team'}, + TableWidgets.CellHeader{children = 'Region'} + ) + end + + if not settings.mainpage then + table.insert(headerCells, TableWidgets.CellHeader{children = 'Roster'}) + end + + local headerRow = TableWidgets.TableHeader{ + children = { + TableWidgets.Row{children = headerCells} + } + } + local regionMap = { + AS = 'Asia', + AM = 'Americas', + EU = 'Europe' + } + + local titleName = 'Global' + + if settings.filterType == 'region' then + titleName = regionMap[settings.filterRegion] or settings.filterRegion + elseif settings.filterType == 'subregion' then + titleName = 'Subregion' + elseif settings.filterType == 'country' then + titleName = settings.filterCountryDisplay + end + + local title = HtmlWidgets.Div { + children = { + HtmlWidgets.Div { + children = { + HtmlWidgets.B { children = 'Unofficial ' .. titleName .. ' VRS' }, + HtmlWidgets.Span { children = 'Last updated: ' .. settings.updated } + }, + classes = { 'ranking-table__top-row-text' } + }, + HtmlWidgets.Div { + children = { + HtmlWidgets.Span { children = 'Data by Liquipedia' }, + }, + classes = { 'ranking-table__top-row-logo-container' } + } + }, + classes = { 'ranking-table__top-row' }, + } + + local columns + if settings.filterType ~= 'none' then + columns = WidgetUtil.collect( + {align = 'center', sortType = 'number'}, + {align = 'center', sortType = 'number'}, + {align = 'center', sortType = 'number'}, + {align = 'left'} + ) + else + columns = WidgetUtil.collect( + {align = 'center', sortType = 'number'}, + {align = 'center', sortType = 'number'}, + {align = 'left'}, + {align = 'center'} + ) + end + + if settings.mainpage then + for _, col in ipairs(columns) do + col.width = (100 / #columns) .. '%' + end + end + + if not settings.mainpage then + table.insert(columns, {align = 'left'}) + end + + local footer = Link { + link = FOOTER_LINK, + linktype = 'internal', + children = { + HtmlWidgets.Div { + children = { 'See Rankings Page', Icon.makeIcon { iconName = 'goto' } }, + classes = { 'ranking-table__footer-button' }, + } + }, + } + + if #standings == 0 then + return HtmlWidgets.Div{ + children = { + HtmlWidgets.B{ children = 'No teams found for the selected filter.' } + }, + css = { padding = '12px' } + } + end + + local tableWidget = TableWidgets.Table{ + title = title, + sortable = false, + columns = columns, + footer = settings.mainpage and footer or nil, + css = settings.mainpage and { width = '100%' } or nil, + children = { + headerRow, + TableWidgets.TableBody{ + children = Array.map(standings, function(entry) + return VRSStandings._row(entry, settings.mainpage) + end) + } + }, + } + + if settings.mainpage then + return HtmlWidgets.Div{ + css = { width = '100%' }, + children = { tableWidget } + } + else + return tableWidget + end +end + +---@private +function VRSStandings:_parse() + local props = self.props + local rankingType = (props.rankingType == 'main') and 'main' or 'live' + local datapointType = (rankingType == 'main') and DATAPOINT_TYPE_MAIN or DATAPOINT_TYPE_LIVE + + local settings = { + title = props.title, + shouldFetch = Logic.readBool(props.shouldFetch), + fetchLimit = tonumber(props.fetchLimit), + filterRegion = props.filterRegion, + filterSubregion = props.filterSubregion, + filterCountry = props.filterCountry, + mainpage = Logic.readBool(props.mainpage), + rankingType = rankingType, + datapointType = datapointType, + } + + if props.updated == 'latest' or not props.updated then + settings.updated = VRSStandings._fetchLatestDate(datapointType) + else + settings.updated = DateExt.toYmdInUtc(props.updated) + end + + -- Only one filter can be applied at once + settings.filterType = 'none' + + if settings.filterRegion then + settings.filterType = 'region' + elseif settings.filterSubregion then + settings.filterType = 'subregion' + elseif settings.filterCountry then + settings.filterType = 'country' + end + + settings.filterCountries = nil + settings.filterCountryDisplay = 'Filtered' + + if settings.filterCountry then + local rawList = mw.text.split(settings.filterCountry, ',') + local countrySet = {} + + for _, raw in ipairs(rawList) do + countrySet[mw.text.trim(raw)] = true + end + + settings.filterCountries = countrySet + settings.filterCountryDisplay = #rawList > 1 and 'Filtered' or mw.text.trim(rawList[1]) + end + + ---@type {points: number, opponent: standardOpponent}[] + local standings = {} + + if settings.shouldFetch then + standings = VRSStandings._fetch(settings.updated, settings.datapointType) + else + Table.iter.forEachPair(self.props, function(key, value) + if not string.match(key, '^%d+$') then + return + end + + local data = Json.parse(value) + + local opponent = Opponent.readOpponentArgs(Table.merge(data, { + type = Opponent.team, + })) + + data[1] = nil + opponent.players = Array.map(Array.range(1,5), FnUtil.curry(Opponent.readPlayerArgs, data)) + + opponent.extradata = opponent.extradata or {} + opponent.extradata.region = data.region + opponent.extradata.subregion = data.subregion + opponent.extradata.country = data.country + + table.insert(standings,{ + place = tonumber(key), + points = tonumber(data.points), + opponent = opponent + }) + end) + + VRSStandings._store(settings.updated, settings.datapointType, standings) + end + + Array.sortInPlaceBy(standings, Operator.property('place')) + + if settings.filterType ~= 'none' then + for i, entry in ipairs(standings) do + entry.global_place = i + end + end + -- filtering + standings = Array.filter(standings, function(entry) + local extradata = entry.opponent.extradata or {} + + if settings.filterType == 'region' then + return extradata.region == settings.filterRegion + end + + if settings.filterType == 'subregion' then + return extradata.subregion == settings.filterSubregion + end + + if settings.filterType == 'country' then + local matchingPlayers = Array.filter(entry.opponent.players, function(player) + return player ~= nil + and player.flag ~= nil + and settings.filterCountries[player.flag] == true + end) + return #matchingPlayers >= 3 + end + + return true + end) + + if settings.fetchLimit then + standings = Array.sub(standings, 1, settings.fetchLimit) + end + + for i, entry in ipairs(standings) do + entry.place = i + end + + return standings, settings +end + +---@private +function VRSStandings._row(standing, mainpage) + local extradata = standing.opponent.extradata or {} + + local cells + if standing.global_place then + cells = WidgetUtil.collect( + TableWidgets.Cell{children = standing.place}, + TableWidgets.Cell{children = standing.global_place}, + TableWidgets.Cell{ + children = MathUtil.formatRounded{value = standing.points, precision = 1} + }, + TableWidgets.Cell{ + children = OpponentDisplay.InlineTeamContainer{ + template = standing.opponent.template + } + } + ) + else + cells = WidgetUtil.collect( + TableWidgets.Cell{children = standing.place}, + TableWidgets.Cell{ + children = MathUtil.formatRounded{value = standing.points, precision = 1} + }, + TableWidgets.Cell{ + children = OpponentDisplay.InlineTeamContainer{ + template = standing.opponent.template + } + }, + TableWidgets.Cell{children = extradata.region or ''} + ) + end + + if not mainpage then + table.insert(cells, + TableWidgets.Cell{ + children = Array.map(standing.opponent.players,function(player) + return HtmlWidgets.Span{ + css = {display="inline-block", width="160px"}, + children = PlayerDisplay.InlinePlayer({player = player}) + } + end) + } + ) + end + + return TableWidgets.Row{children = cells} +end + +---@private +function VRSStandings._store(updated, datapointType, standings) + if Lpdb.isStorageDisabled() then + return + end + + local dataPoint = Lpdb.DataPoint:new{ + objectname = datapointType .. '_' .. updated, + type = datapointType, + name = 'Inofficial VRS (' .. updated .. ')', + date = updated, + extradata = standings + } + + dataPoint:save() +end + +---@private +function VRSStandings._fetch(updated, datapointType) + local conditions = Condition.Tree(BooleanOperator.all):add{ + Condition.Node(Condition.ColumnName('date'), Comparator.eq, updated), + Condition.Node(Condition.ColumnName('namespace'), Comparator.eq, 0), + } + + if datapointType == DATAPOINT_TYPE_MAIN then + conditions:add{ + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_MAIN), + } + else + conditions:add{ + Condition.Tree(BooleanOperator.any):add{ + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_LIVE), + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_MAIN), + } + } + end + + local data = mw.ext.LiquipediaDB.lpdb('datapoint', { + conditions = conditions:toString(), + query = 'extradata', + limit = 1, + }) + + assert(data[1], 'No VRS data found for type "' .. datapointType .. '" on date "' .. updated .. '"') + return data[1].extradata +end + +---@private +function VRSStandings._fetchLatestDate(datapointType) + local conditions = Condition.Tree(BooleanOperator.all):add{ + Condition.Node(Condition.ColumnName('namespace'), Comparator.eq, 0), + } + + if datapointType == DATAPOINT_TYPE_MAIN then + conditions:add{ + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_MAIN), + } + else + conditions:add{ + Condition.Tree(BooleanOperator.any):add{ + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_LIVE), + Condition.Node(Condition.ColumnName('type'), Comparator.eq, DATAPOINT_TYPE_MAIN), + } + } + end + + local data = mw.ext.LiquipediaDB.lpdb('datapoint', { + conditions = conditions:toString(), + query = 'date', + order = 'date desc', + limit = 1, + }) + + assert(data[1], 'No VRS data found for type "' .. datapointType .. '"') + return DateExt.toYmdInUtc(DateExt.parseIsoDate(data[1].date)) +end + +return VRSStandings From d4a1cfb7d64567b2a7463dd816f774c251d96836 Mon Sep 17 00:00:00 2001 From: mischiefcs Date: Thu, 19 Mar 2026 18:32:00 +0000 Subject: [PATCH 2/4] resolving comment as well as check errors --- lua/definitions/liquipedia_db.lua | 1 - lua/wikis/commons/Mock/Lpdb.lua | 1 - lua/wikis/commons/PrizePool/Award/Placement.lua | 4 +++- lua/wikis/counterstrike/Infobox/League/Custom.lua | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lua/definitions/liquipedia_db.lua b/lua/definitions/liquipedia_db.lua index 9b332ec9e00..f62238aef37 100644 --- a/lua/definitions/liquipedia_db.lua +++ b/lua/definitions/liquipedia_db.lua @@ -39,7 +39,6 @@ local lpdb = {} ---@field placement string ---@field prizemoney number ---@field individualprizemoney number ----@field playershare number ---@field prizepoolindex integer ---@field weight number ---@field mode string diff --git a/lua/wikis/commons/Mock/Lpdb.lua b/lua/wikis/commons/Mock/Lpdb.lua index b04a628ba09..92f3bf8b953 100644 --- a/lua/wikis/commons/Mock/Lpdb.lua +++ b/lua/wikis/commons/Mock/Lpdb.lua @@ -62,7 +62,6 @@ dbStructure.placement = { placement = 'number|string|nil', prizemoney = 'number?', individualprizemoney = 'number?', - playershare = 'number?', prizepoolindex = 'number?', weight = 'number?', mode = 'string?', diff --git a/lua/wikis/commons/PrizePool/Award/Placement.lua b/lua/wikis/commons/PrizePool/Award/Placement.lua index 41917ecc403..4334e54fe1b 100644 --- a/lua/wikis/commons/PrizePool/Award/Placement.lua +++ b/lua/wikis/commons/PrizePool/Award/Placement.lua @@ -80,7 +80,9 @@ function AwardPlacement:_getLpdbData(...) local lpdbData = { date = opponent.date, prizemoney = prizeMoney, - individualprizemoney = Opponent.typeIsParty(opponentType) and ((playerShare or prizeMoney) / Opponent.partySize(opponentType)) or 0, + individualprizemoney = Opponent.typeIsParty(opponentType) + and ((playerShare or prizeMoney) / Opponent.partySize(opponentType)) + or 0, playerShare = not Opponent.typeIsParty(opponentType) and playerShare or nil, mode = 'award_individual', weight = 0, diff --git a/lua/wikis/counterstrike/Infobox/League/Custom.lua b/lua/wikis/counterstrike/Infobox/League/Custom.lua index 2e5a3b3e2ae..45da88ab040 100644 --- a/lua/wikis/counterstrike/Infobox/League/Custom.lua +++ b/lua/wikis/counterstrike/Infobox/League/Custom.lua @@ -87,7 +87,11 @@ local VALVE_TIERS = { ['tier 1 qualifier'] = {meta = 'Valve Tier 1 qualifier', name = 'Tier 1 Qualifier', link = 'Valve Tier 1 Events'}, ['tier 2'] = {meta = 'Valve Tier 2 event', name = 'Tier 2', link = 'Valve Tier 2 Events'}, ['tier 2 qualifier'] = {meta = 'Valve Tier 2 qualifier', name = 'Tier 2 Qualifier', link = 'Valve Tier 2 Events'}, - ['tier 2 open sign ups'] = {meta = 'Valve Tier 2 open sign-up', name = 'Tier 2 Open Sign-up', link = 'Valve Tier 2 Events'}, + ['tier 2 open sign ups'] = { + meta = 'Valve Tier 2 open sign-up', + name = 'Tier 2 Open Sign-up', + link = 'Valve Tier 2 Events' + }, ['wildcard'] = {meta = 'Valve Wildcard event', name = 'Wildcard', link = 'Valve Wildcard Events'}, ['tier 1 wildcard'] = {meta = 'Valve Tier 1 Wildcard event', name = 'Tier 1 Wildcard', link = 'Valve Wildcard Events'}, ['tier 2 wildcard'] = {meta = 'Valve Tier 2 Wildcard event', name = 'Tier 2 Wildcard', link = 'Valve Wildcard Events'}, From 342b2abadd97baf713f833e181b7a1242a42cd56 Mon Sep 17 00:00:00 2001 From: mischiefcs Date: Thu, 19 Mar 2026 18:39:07 +0000 Subject: [PATCH 3/4] removing playershare --- .../commons/PrizePool/Award/Placement.lua | 7 +-- lua/wikis/commons/PrizePool/Base.lua | 54 ++++--------------- lua/wikis/commons/PrizePool/Placement.lua | 3 -- .../commons/TeamParticipants/Repository.lua | 7 --- 4 files changed, 11 insertions(+), 60 deletions(-) diff --git a/lua/wikis/commons/PrizePool/Award/Placement.lua b/lua/wikis/commons/PrizePool/Award/Placement.lua index 4334e54fe1b..b64c29a90e2 100644 --- a/lua/wikis/commons/PrizePool/Award/Placement.lua +++ b/lua/wikis/commons/PrizePool/Award/Placement.lua @@ -18,7 +18,6 @@ local _tbd_index = 0 local PRIZE_TYPE_BASE_CURRENCY = 'BASE_CURRENCY' local PRIZE_TYPE_POINTS = 'POINTS' -local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' --- An AwardPlacement is a set of opponents who all share the same award in the tournament. --- Its input is generally a table created by `Template:Slot`. @@ -76,14 +75,10 @@ function AwardPlacement:_getLpdbData(...) local prizeMoney = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_BASE_CURRENCY .. 1)) or 0 local pointsReward = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 1) local pointsReward2 = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 2) - local playerShare = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_PLAYER_SHARE .. 1)) local lpdbData = { date = opponent.date, prizemoney = prizeMoney, - individualprizemoney = Opponent.typeIsParty(opponentType) - and ((playerShare or prizeMoney) / Opponent.partySize(opponentType)) - or 0, - playerShare = not Opponent.typeIsParty(opponentType) and playerShare or nil, + individualprizemoney = Opponent.typeIsParty(opponentType) and (prizeMoney / Opponent.partySize(opponentType)) or 0, mode = 'award_individual', weight = 0, extradata = { diff --git a/lua/wikis/commons/PrizePool/Base.lua b/lua/wikis/commons/PrizePool/Base.lua index a0b68179783..680786f4314 100644 --- a/lua/wikis/commons/PrizePool/Base.lua +++ b/lua/wikis/commons/PrizePool/Base.lua @@ -10,10 +10,12 @@ local Lua = require('Module:Lua') local Abbreviation = Lua.import('Module:Abbreviation') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') +local DateExt = Lua.import('Module:Date/Ext') local Json = Lua.import('Module:Json') local LeagueIcon = Lua.import('Module:LeagueIcon') local Logic = Lua.import('Module:Logic') local Lpdb = Lua.import('Module:Lpdb') +local MathUtil = Lua.import('Module:MathUtil') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') @@ -49,8 +51,6 @@ local BasePrizePool = Class.new(function(self, ...) self:init(...) end) ---@field index integer ---@field data table -local TODAY = os.date('%Y-%m-%d') --[[@as string]] - local LANG = mw.language.getContentLanguage() local DASH = '-' local NON_BREAKING_SPACE = ' ' @@ -63,7 +63,6 @@ local PRIZE_TYPE_QUALIFIES = 'QUALIFIES' local PRIZE_TYPE_POINTS = 'POINTS' local PRIZE_TYPE_PERCENTAGE = 'PERCENT' local PRIZE_TYPE_FREETEXT = 'FREETEXT' -local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' BasePrizePool.config = { showBaseCurrency = { @@ -90,14 +89,14 @@ BasePrizePool.config = { cutafter = { default = 4, read = function(args) - return tonumber(args.cutafter) + return MathUtil.toInteger(args.cutafter) end }, hideafter = { default = math.huge, read = function(args) - local hideAfter = tonumber(args.hideafter) - local cutAfter = tonumber(args.cutafter) or 4 + local hideAfter = MathUtil.toInteger(args.hideafter) + local cutAfter = MathUtil.toInteger(args.cutafter) or 4 if not hideAfter then return end @@ -358,30 +357,6 @@ BasePrizePool.prizeTypes = { end end, }, - [PRIZE_TYPE_PLAYER_SHARE] = { - sortOrder = 55, - - header = 'playershare', - headerParse = function (prizePool, input, context, index) - return {title = 'Player Share'} - end, - headerDisplay = function (data) - return TableCell{children = {data.title}} - end, - - row = 'playershare', - rowParse = function (placement, input, context, index) - return BasePrizePool._parseInteger(input) - end, - rowDisplay = function (headerData, data) - if data > 0 then - return TableCell{children = { - Currency.display(BASE_CURRENCY, data, - {formatValue = true, formatPrecision = headerData.roundPrecision, displayCurrencyCode = false}) - }} - end - end, - }, [PRIZE_TYPE_FREETEXT] = { sortOrder = 60, @@ -411,7 +386,7 @@ function BasePrizePool:init(args) self.args = self:_parseArgs(args) self.pagename = mw.title.getCurrentTitle().text - self.date = BasePrizePool._getTournamentDate() + self.date = DateExt.getContextualDateOrNow() self.opponentType = self.args.type self.options = {} @@ -798,12 +773,9 @@ function BasePrizePool:_currencyExchangeInfo() end -- The exchange date display should not be in the future, as the extension uses current date for those. - local exchangeDate = self.date - if exchangeDate > TODAY then - exchangeDate = TODAY - end - - local exchangeDateText = LANG:formatDate('M j, Y', exchangeDate) + local exchangeDateText = DateExt.formatTimestamp( + 'M j, Y', math.min(DateExt.getCurrentTimestamp(), DateExt.readTimestamp(self.date)) + ) local wrapper = mw.html.create('small') @@ -823,7 +795,7 @@ end ---@return string function BasePrizePool._CurrencyConvertionText(prize) local exchangeRate = BasePrizePool.prizeTypes[PRIZE_TYPE_LOCAL_CURRENCY].convertToBaseCurrency( - prize.data, 1, BasePrizePool._getTournamentDate() + prize.data, 1, DateExt.getContextualDateOrNow() ) return Currency.display(prize.data.currency, 1) .. ' ≃ ' .. @@ -871,12 +843,6 @@ function BasePrizePool:assertOpponentStructType(typeStruct) end end ---- Returns the default date based on wiki-variables set in the Infobox League ----@return string -function BasePrizePool._getTournamentDate() - return Variables.varDefault('tournament_enddate', TODAY) -end - ---@return self function BasePrizePool:storeData() local prizePoolIndex = (tonumber(Variables.varDefault('prizepool_index')) or 0) + 1 diff --git a/lua/wikis/commons/PrizePool/Placement.lua b/lua/wikis/commons/PrizePool/Placement.lua index ee0d92256b8..3e11a0935b8 100644 --- a/lua/wikis/commons/PrizePool/Placement.lua +++ b/lua/wikis/commons/PrizePool/Placement.lua @@ -26,7 +26,6 @@ local DASH = '-' local PRIZE_TYPE_BASE_CURRENCY = 'BASE_CURRENCY' local PRIZE_TYPE_POINTS = 'POINTS' local PRIZE_TYPE_QUALIFIES = 'QUALIFIES' -local PRIZE_TYPE_PLAYER_SHARE = 'PLAYER_SHARE' -- Allowed none-numeric score values. local SPECIAL_SCORES = {'W', 'FF' , 'L', 'DQ', 'D'} @@ -236,7 +235,6 @@ function Placement:_getLpdbData(...) local pointsReward = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 1) local pointsReward2 = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_POINTS .. 2) local isQualified = self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_QUALIFIES .. '1') - local playerShare = tonumber(self:getPrizeRewardForOpponent(opponent, PRIZE_TYPE_PLAYER_SHARE .. 1)) or 0 local lpdbData = { image = image, @@ -264,7 +262,6 @@ function Placement:_getLpdbData(...) participantteam = (opponentType == Opponent.solo and players.p1team) and Opponent.toName{template = players.p1team, type = 'team', extradata = {}} or nil, - playershare = playerShare and tostring(playerShare) or nil, }, qualified = isQualified and 1 or 0 -- TODO: We need to create additional LPDB Fields diff --git a/lua/wikis/commons/TeamParticipants/Repository.lua b/lua/wikis/commons/TeamParticipants/Repository.lua index 79cc9ffd9b8..26a9629f4c6 100644 --- a/lua/wikis/commons/TeamParticipants/Repository.lua +++ b/lua/wikis/commons/TeamParticipants/Repository.lua @@ -101,13 +101,6 @@ function TeamParticipantsRepository.save(participant) lpdbData.individualprizemoney = lpdbData.prizemoney / numberOfPlayersOnTeam end - -- Calculate individual playerShare - if lpdbData.playershare then - if activeOpponent.type ~= Opponent.team then - lpdbData.individualprizemoney = lpdbData.playershare - end - end - mw.ext.LiquipediaDB.lpdb_placement(lpdbData.objectName, Json.stringifySubTables(lpdbData)) end From 4c313aed3cc8130d6e76633e106a155ac8d15aec Mon Sep 17 00:00:00 2001 From: mischiefcs Date: Thu, 19 Mar 2026 18:44:14 +0000 Subject: [PATCH 4/4] removing tier change & restoring to current --- .../counterstrike/Infobox/League/Custom.lua | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/lua/wikis/counterstrike/Infobox/League/Custom.lua b/lua/wikis/counterstrike/Infobox/League/Custom.lua index 45da88ab040..a0aa775aa81 100644 --- a/lua/wikis/counterstrike/Infobox/League/Custom.lua +++ b/lua/wikis/counterstrike/Infobox/League/Custom.lua @@ -9,8 +9,10 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') -local Logic = Lua.import('Module:Logic') +local FnUtil = Lua.import('Module:FnUtil') local Json = Lua.import('Module:Json') +local Logic = Lua.import('Module:Logic') +local Operator = Lua.import('Module:Operator') local Page = Lua.import('Module:Page') local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') @@ -30,6 +32,9 @@ local Widgets = Lua.import('Module:Widget/All') local Cell = Widgets.Cell local Title = Widgets.Title local Center = Widgets.Center +local IconFontawesome = Lua.import('Module:Widget/Image/Icon/Fontawesome') +local Link = Lua.import('Module:Widget/Basic/Link') +local WidgetUtil = Lua.import('Module:Widget/Util') ---@class CounterstrikeLeagueInfobox: InfoboxLeague ---@field gameData table @@ -85,16 +90,19 @@ local VALVE_TIERS = { ['rmr event'] = {meta = 'Regional Major Rankings event', name = 'RMR Event', link = 'Regional Major Rankings'}, ['tier 1'] = {meta = 'Valve Tier 1 event', name = 'Tier 1', link = 'Valve Tier 1 Events'}, ['tier 1 qualifier'] = {meta = 'Valve Tier 1 qualifier', name = 'Tier 1 Qualifier', link = 'Valve Tier 1 Events'}, + ['tier 1 wildcard'] = {meta = 'Valve Tier 1 Wildcard event', name = 'Tier 1 Wildcard', link = 'Valve Wildcard Events'}, ['tier 2'] = {meta = 'Valve Tier 2 event', name = 'Tier 2', link = 'Valve Tier 2 Events'}, ['tier 2 qualifier'] = {meta = 'Valve Tier 2 qualifier', name = 'Tier 2 Qualifier', link = 'Valve Tier 2 Events'}, - ['tier 2 open sign ups'] = { - meta = 'Valve Tier 2 open sign-up', - name = 'Tier 2 Open Sign-up', - link = 'Valve Tier 2 Events' - }, - ['wildcard'] = {meta = 'Valve Wildcard event', name = 'Wildcard', link = 'Valve Wildcard Events'}, - ['tier 1 wildcard'] = {meta = 'Valve Tier 1 Wildcard event', name = 'Tier 1 Wildcard', link = 'Valve Wildcard Events'}, ['tier 2 wildcard'] = {meta = 'Valve Tier 2 Wildcard event', name = 'Tier 2 Wildcard', link = 'Valve Wildcard Events'}, + ['wildcard'] = {meta = 'Valve Wildcard event', name = 'Wildcard', link = 'Valve Wildcard Events'}, +} + +local VALVE_TOR_START_DATE = '2025-01-01' +local VALVE_TOR_ENABLED_TIERS = { + VALVE_TIERS.major, + VALVE_TIERS['tier 1'], + VALVE_TIERS['tier 1 qualifier'], + VALVE_TIERS['tier 1 wildcard'] } local RESTRICTIONS = { @@ -177,20 +185,17 @@ function CustomInjector:parse(id, widgets) table.insert(widgets, Center{children = {table.concat(maps, ' • ')}}) end elseif id == 'liquipediatier' then - table.insert( - widgets, + Array.appendWith(widgets, Cell{ name = '[[File:ESL 2019 icon.png|20x20px|link=|ESL|alt=ESL]] Pro Tour Tier', children = {self.caller:_createEslProTierCell(args.eslprotier)}, classes = {'infobox-icon-small'} - } - ) - table.insert( - widgets, + }, Cell{ name = Template.safeExpand(mw.getCurrentFrame(), 'Valve/infobox') .. ' Tier', - children = {self.caller:_createValveTierCell()}, - classes = {'valvepremier-highlighted'} + content = self.caller:_createValveTierCell(), + classes = {'valvepremier-highlighted'}, + options = {separator = ' '} } ) elseif id == 'gamesettings' then @@ -384,10 +389,25 @@ function CustomLeague:_createEslProTierCell(eslProTier) end end ----@return string? +---@return Widget[]? function CustomLeague:_createValveTierCell() if self.valveTier then - return '[[' .. self.valveTier.link .. '|' .. self.valveTier.name .. ']]' + local showInfoIcon = self.data.endDate + and self.data.endDate >= VALVE_TOR_START_DATE + and Array.find(VALVE_TOR_ENABLED_TIERS, FnUtil.curry(Operator.eq, self.valveTier)) + return WidgetUtil.collect( + Link{ + children = {self.valveTier.name}, + link = self.valveTier.link + }, + showInfoIcon and Link{ + children = {IconFontawesome{ + iconName = 'general-info', + hover = 'Click for further details', + }}, + link = '#Valve Operational Requirements' + } or nil + ) end end