Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg
+++ binaries/data/config/default.cfg
@@ -365,6 +365,9 @@
server = "lobby.wildfiregames.com" ; Address of lobby server
xpartamupp = "wfgbot22" ; Name of the server-side xmpp client that manage games
+[lobby.columns]
+averagerating = false ; Show the average rating of the participating players in a column of the gamelist
+
[mod]
enabledmods = "mod public"
Index: binaries/data/mods/public/gui/lobby/lobby.js
===================================================================
--- binaries/data/mods/public/gui/lobby/lobby.js
+++ binaries/data/mods/public/gui/lobby/lobby.js
@@ -219,10 +219,35 @@
Engine.LobbyClearPresenceUpdates();
updatePlayerList();
updateSubject(Engine.LobbyGetRoomSubject());
+ updateLobbyColumns();
Engine.GetGUIObjectByName("chatInput").tooltip = colorizeAutocompleteHotkey();
}
+function updateLobbyColumns()
+{
+ let averageRating = Engine.ConfigDB_GetValue("user", "lobby.columns.averagerating") == "true";
+
+ // Only show the selected columns
+ let gamesBox = Engine.GetGUIObjectByName("gamesBox");
+ gamesBox.hidden_mapType = averageRating;
+ gamesBox.hidden_averageRating = !averageRating;
+
+ // Only show the filters of selected columns
+ let mapTypeFilter = Engine.GetGUIObjectByName("mapTypeFilter");
+ mapTypeFilter.hidden = averageRating;
+ let averageRatingFilter = Engine.GetGUIObjectByName("averageRatingFilter");
+ averageRatingFilter.hidden = !averageRating;
+
+ // Keep filters right above the according column
+ // TODO: Ideally we could read the size of the columns of the COList instead
+ let playersNumberFilter = Engine.GetGUIObjectByName("playersNumberFilter");
+ let size = playersNumberFilter.size;
+ size.rleft = averageRating ? 74: 90;
+ size.rright = averageRating ? 84: 100;
+ playersNumberFilter.size = size;
+}
+
function returnToMainMenu()
{
Engine.StopXmppClient();
@@ -244,6 +269,16 @@
mapTypeFilter.list = [translateWithContext("map", "Any")].concat(g_MapTypes.Title);
mapTypeFilter.list_data = [""].concat(g_MapTypes.Name);
+ let averageRatingOptions = ["<1000", "<1100","<1200",">1200",">1300",">1400",">1500"].reverse();
+ averageRatingOptions = prepareForDropdown(averageRatingOptions.map(r => ({
+ "value": r,
+ "label": sprintf(r[0] == ">" ? translate("> %(rating)s") : translate("< %(rating)s"), { "rating": r.substr(1) })
+ })))
+
+ let averageRatingFilter = Engine.GetGUIObjectByName("averageRatingFilter");
+ averageRatingFilter.list = [translateWithContext("map", "Any")].concat(averageRatingOptions.label);
+ averageRatingFilter.list_data = [""].concat(averageRatingOptions.value);
+
resetFilters();
}
@@ -252,6 +287,7 @@
Engine.GetGUIObjectByName("mapSizeFilter").selected = 0;
Engine.GetGUIObjectByName("playersNumberFilter").selected = 0;
Engine.GetGUIObjectByName("mapTypeFilter").selected = g_MapTypes.Default;
+ Engine.GetGUIObjectByName("averageRatingFilter").selected = 0;
Engine.GetGUIObjectByName("showFullFilter").checked = false;
applyFilters();
@@ -274,6 +310,7 @@
let mapSizeFilter = Engine.GetGUIObjectByName("mapSizeFilter");
let playersNumberFilter = Engine.GetGUIObjectByName("playersNumberFilter");
let mapTypeFilter = Engine.GetGUIObjectByName("mapTypeFilter");
+ let averageRatingFilter = Engine.GetGUIObjectByName("averageRatingFilter");
let showFullFilter = Engine.GetGUIObjectByName("showFullFilter");
// We assume index 0 means display all for any given filter.
@@ -292,6 +329,14 @@
if (!showFullFilter.checked && game.maxnbp <= game.nbp)
return true;
+ if (averageRatingFilter.selected > 0)
+ {
+ let selected = averageRatingFilter.list_data[averageRatingFilter.selected];
+ if (selected.startsWith(">") && +selected.substr(1) >= game.averageRating ||
+ selected.startsWith("<") && +selected.substr(1) <= game.averageRating)
+ return true;
+ }
+
return false;
}
@@ -530,19 +575,44 @@
g_SelectedGamePort = g_GameList[gamesBox.selected].port;
}
- g_GameList = Engine.GetGameList().filter(game => !filterGame(game)).sort((a, b) => {
+ let testList = [{name:"Partida de pablek2",ip:"bla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"0":\\[{"Name":"pablek2 (1269)","Team":0}],"1":\\[{"Name":"Raulyo (875)","Team":1}]}',mapName:"maps/random/marmara",niceMapName:"Marmara",mapSize:"320",mapType:"random",victoryCondition:"Conquista",startTime:"1487082783"},{name:"Reaperisonline's game",ip:"bla",port:"20595",state:"waiting",nbp:"5",maxnbp:"6",players:'{"0":\\[{"Name":"Reaperisonline (1259)","Team":0},{"Name":"Sh4d0w3rPL (1387)","Team":0}],"1":\\[{"Name":"jtggamer (1103)","Team":1},{"Name":"temik5 (1033)","Team":1},{"Name":"WGold (1180)","Team":1},{"Name":"siliboss (1143)","Team":1,"Offline":true,"State":"defeated"}]}',mapName:"maps/random/fortress",niceMapName:"Fortress",mapSize:"320",mapType:"random",victoryCondition:"Conquest",startTime:"1487081792"},{name:"siole's game",ip:"blabla",port:"20595",state:"running",nbp:"8",maxnbp:"8",players:'{"-1":\\[{"Name":"siole","Team":-1},{"Name":"Grugnas (1417)","Team":-1},{"Name":"merlin1 (1564)","Team":-1},{"Name":"snelius (1365)","Team":-1},{"Name":"imrobbyg (1622)","Team":-1},{"Name":"PrincipalityOfZeon (1652)","Team":-1},{"Name":"jaxtrx2 (1030)","Team":-1},{"Name":"nigel87 (1530)","Team":-1}],"observer":\\[{"Name":"fpre (1545)","Team":"observer"},{"Name":"Achelao (1418)","Team":"observer"},{"Name":"elexis3 (1156)","Team":"observer"}]}',mapName:"maps/random/survivalofthefittest",niceMapName:"Survival of the Fittest",mapSize:"384",mapType:"random",victoryCondition:"Regicide",startTime:"1486938980"},{name:"1v1",ip:"blabla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"-1":\\[{"Name":"borg- (2114)","Team":-1},{"Name":"Feldfeld (1638)","Team":-1}]}',mapName:"maps/random/mainland",niceMapName:"Mainland",mapSize:"384",mapType:"random",victoryCondition:"Conquest",startTime:"1486532180"},{name:"Partida de JeanClaude",ip:"blabla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"-1":\\[{"Name":"JeanClaude (1653)","Team":-1},{"Name":"Liberty (1569)","Team":-1}]}',mapName:"maps/random/mainland",niceMapName:"Mainland",mapSize:"384",mapType:"random",victoryCondition:"Conquest",startTime:"1486523148"},{name:"Komenoss spel",ip:"blabla",port:"20595",state:"running",nbp:"4",maxnbp:"4",players:'{"-1":\\[{"Name":"Komenos","Team":-1},{"Name":"Jordi_Iranzo93 (1278)","Team":-1},{"Name":"META-BARONS (1393)","Team":-1},{"Name":"King_Jerusalem (1265)","Team":-1}]}',mapName:"maps/random/bahrain",niceMapName:"Bahrain",mapSize:"384",mapType:"random",victoryCondition:"Erövring",startTime:"1487084910"},{name:"Partida de freedomm",ip:"blabla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"0":\\[{"Name":"freedomm (1298)","Team":0}],"1":\\[{"Name":"bill13986 (1028)","Team":1}]}',mapName:"maps/skirmishes/Lorraine Plain (2)",niceMapName:"Lorraine Plain (2)",mapSize:"Default",mapType:"skirmish",victoryCondition:"Conquista",startTime:"1487085137"},{name:"Partida de comandantelobo",ip:"blabla",port:"20595",state:"running",nbp:"4",maxnbp:"4",players:'{"0":\\[{"Name":"comandantelobo (1047)","Team":0},{"Name":"perro (1153)","Team":0}],"1":\\[{"Name":"akshayhalasangi","Team":1},{"Name":"sckt (1263)","Team":1}]}',mapName:"maps/random/mainland",niceMapName:"Mainland",mapSize:"256",mapType:"random",victoryCondition:"Conquista",startTime:"1487083419"},{name:"Partie de mazert",ip:"blabla",port:"20595",state:"init",nbp:"4",maxnbp:"4",players:'{"-1":\\[{"Name":"mazert (1224)"},{"Name":"HirnWolf (1149)"},{"Name":"siliboss (1143)"},{"Name":"Ivaylo_Uzunov (1085)"}]}',mapName:"maps/random/frontier",niceMapName:"Frontier",mapSize:"256",mapType:"random",victoryCondition:"Conquête",startTime:""},{name:"mord's game",ip:"blabla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"0":\\[{"Name":"mord (1165)","Team":0}],"1":\\[{"Name":"Chrisf1 (1222)","Team":1}]}',mapName:"maps/random/unknown",niceMapName:"Unknown",mapSize:"256",mapType:"random",victoryCondition:"Conquest",startTime:"1487082144"},{name:"craqqy's game",ip:"blabla",port:"20595",state:"running",nbp:"2",maxnbp:"2",players:'{"-1":\\[{"Name":"craqqy","Team":-1},{"Name":"KeaneY","Team":-1}]}',mapName:"maps/skirmishes/Acropolis Bay (2)",niceMapName:"Acropolis Bay (2)",mapSize:"Default",mapType:"skirmish",victoryCondition:"Conquest",startTime:"1487084573"},{name:"GummionkelchenIsBack's Spiel",ip:"blabla",port:"20595",state:"waiting",nbp:"5",maxnbp:"6",players:'{"0":\\[{"Name":"GummionkelchenIsBack (1396)","Team":0},{"Name":"Jordi_Iranzo93 (1278)","Team":0,"Offline":true},{"Name":"zDiegoAC","Team":0}],"1":\\[{"Name":"yashbanka123 (1141)","Team":1},{"Name":"TheRolle","Team":1},{"Name":"Rexosts (1342)","Team":1}]}',mapName:"maps/random/unknown_land",niceMapName:"Unknown Land",mapSize:"256",mapType:"random",victoryCondition:"Eroberung",startTime:"1487084209"},{name:"noobiel's game",ip:"blabla",port:"20595",state:"running",nbp:"1",maxnbp:"2",players:'{"-1":\\[{"Name":"noobiel","Team":-1},{"Name":"Ptolemy Epigone","Team":-1,"AI":"petra","AIDiff":3}]}',mapName:"maps/skirmishes/Greek Acropolis (2)",niceMapName:"Greek Acropolis (2)",mapSize:"Default",mapType:"skirmish",victoryCondition:"Conquest",startTime:"1486821890"}];
+
+ g_GameList = /*Engine.GetGameList()*/testList.map(game => {
+
+ game.niceMapName = translateMapTitle(game.niceMapName);
+
+ // Compute average rating of participating clients
+ let playerRatings = [];
+ for (let player of stringifiedTeamListToPlayerData(game.players))
+ {
+ if (player.Team == "observer")
+ continue;
+
+ let result = /^\S+\ \((\d+)\)$/g.exec(player.Name);
+ playerRatings.push(result ? +result[1] : 1200);
+ }
+
+ game.averageRating =
+ playerRatings.length ?
+ Math.round(playerRatings.reduce((sum, current) => sum + current) / playerRatings.length) :
+ 1200;
+
+ return game;
+
+ }).filter(game => !filterGame(game)).sort((a, b) => {
let sortA, sortB;
switch (sortBy)
{
case 'name':
case 'mapSize':
case 'mapType':
+ case 'averageRating':
sortA = a[sortBy];
sortB = b[sortBy];
break;
case 'mapName':
- sortA = translate(a.niceMapName);
- sortB = translate(b.niceMapName);
+ sortA = a.niceMapName;
+ sortB = b.niceMapName;
break;
case 'nPlayers':
sortA = a.maxnbp;
@@ -564,6 +634,7 @@
let list_mapSize = [];
let list_mapType = [];
let list_nPlayers = [];
+ let list_averageRating = [];
let list = [];
let list_data = [];
let selectedGameIndex = -1;
@@ -578,10 +649,11 @@
selectedGameIndex = +i;
list_name.push('[color="' + g_GameColors[game.state] + '"]' + gameName);
- list_mapName.push(translateMapTitle(game.niceMapName));
+ list_mapName.push(game.niceMapName);
list_mapSize.push(translateMapSize(game.mapSize));
list_mapType.push(g_MapTypes.Title[mapTypeIdx] || "");
list_nPlayers.push(game.nbp + "/" + game.maxnbp);
+ list_averageRating.push(game.averageRating);
list.push(gameName);
list_data.push(i);
}
@@ -591,6 +663,8 @@
gamesBox.list_mapSize = list_mapSize;
gamesBox.list_mapType = list_mapType;
gamesBox.list_nPlayers = list_nPlayers;
+ gamesBox.list_averageRating = list_averageRating;
+
// Change these last, otherwise crash
gamesBox.list = list;
gamesBox.list_data = list_data;
@@ -613,7 +687,7 @@
if (!game)
return;
- Engine.GetGUIObjectByName("sgMapName").caption = translateMapTitle(game.niceMapName);
+ Engine.GetGUIObjectByName("sgMapName").caption = game.niceMapName;
let sgGameStartTime = Engine.GetGUIObjectByName("sgGameStartTime");
let sgNbPlayers = Engine.GetGUIObjectByName("sgNbPlayers");
Index: binaries/data/mods/public/gui/lobby/lobby.xml
===================================================================
--- binaries/data/mods/public/gui/lobby/lobby.xml
+++ binaries/data/mods/public/gui/lobby/lobby.xml
@@ -199,7 +199,7 @@
updateGameSelection();
applyFilters();
joinButton();
-
+
Name
@@ -211,16 +211,20 @@
Type
-
+
Players
+
+ Rating
+
+
Index: binaries/data/mods/public/gui/options/options.json
===================================================================
--- binaries/data/mods/public/gui/options/options.json
+++ binaries/data/mods/public/gui/options/options.json
@@ -257,6 +257,12 @@
"label": "Chat Backlog",
"tooltip": "Number of backlogged messages to load when joining the lobby",
"parameters": { "config": "lobby.history", "min": "0" }
+ },
+ {
+ "type": "boolean",
+ "label": "Average Player Rating Column",
+ "tooltip": "Show the average rating of the participating players in a column of the gamelist.",
+ "parameters": { "config": "lobby.columns.averagerating" }
}
]
}
Index: source/gui/COList.cpp
===================================================================
--- source/gui/COList.cpp
+++ source/gui/COList.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016 Wildfire Games.
+/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -148,6 +148,11 @@
float xpos = 0;
for (COListColumn column : m_Columns)
{
+ bool hidden = false;
+ GUI::GetSetting(this, "hidden_" + column.m_Id, hidden);
+ if (hidden)
+ continue;
+
float width = column.m_Width;
// Check if it's a decimal value, and if so, assume relative positioning.
if (column.m_Width < 1 && column.m_Width > 0)
@@ -271,6 +276,8 @@
m_Columns.push_back(column);
AddSetting(GUIST_CGUIList, "list_" + column.m_Id);
+ AddSetting(GUIST_bool, "hidden_" + column.m_Id);
+
SetupText();
return true;
@@ -372,6 +379,11 @@
float xpos = 0;
for (size_t col = 0; col < m_Columns.size(); ++col)
{
+ bool hidden = false;
+ GUI::GetSetting(this, "hidden_" + m_Columns[col].m_Id, hidden);
+ if (hidden)
+ continue;
+
// Check if it's a decimal value, and if so, assume relative positioning.
float width = m_Columns[col].m_Width;
if (m_Columns[col].m_Width < 1 && m_Columns[col].m_Width > 0)
@@ -432,6 +444,11 @@
xpos = 0;
for (size_t col = 0; col < objectsCount; ++col)
{
+ bool hidden = false;
+ GUI::GetSetting(this, "hidden_" + m_Columns[col].m_Id, hidden);
+ if (hidden)
+ continue;
+
// Determine text position and width
const CPos textPos = rect.TopLeft() + CPos(xpos, -scroll + m_ItemsYPositions[i]);