From 19bd3a4f5fb820b95204b9cd1035f0b5e7a2deb8 Mon Sep 17 00:00:00 2001 From: Freddy Date: Thu, 3 Feb 2022 14:03:21 +0000 Subject: [PATCH] Add Terms of Service Popup and server-specific Terms of Service tab Author Freddy, contributed by z411, minor contributions by Mario, LegendaryGuard and terencehill --- qcsrc/common/constants.qh | 13 +- qcsrc/common/playerstats.qc | 4 + qcsrc/lib/urllib.qh | 1 + qcsrc/menu/xonotic/_mod.inc | 4 + qcsrc/menu/xonotic/_mod.qh | 4 + qcsrc/menu/xonotic/dialog_firstrun.qc | 5 + qcsrc/menu/xonotic/dialog_firstrun.qh | 1 + .../dialog_multiplayer_join_serverinfo.qc | 147 +++++++----------- .../dialog_multiplayer_join_serverinfo.qh | 59 +++---- .../dialog_multiplayer_join_serverinfotab.qc | 107 +++++++++++++ .../dialog_multiplayer_join_serverinfotab.qh | 30 ++++ .../dialog_multiplayer_join_termsofservice.qc | 62 ++++++++ .../dialog_multiplayer_join_termsofservice.qh | 18 +++ qcsrc/menu/xonotic/dialog_termsofservice.qc | 102 ++++++++++++ qcsrc/menu/xonotic/dialog_termsofservice.qh | 24 +++ qcsrc/menu/xonotic/mainwindow.qc | 24 +-- qcsrc/menu/xonotic/mainwindow.qh | 3 +- qcsrc/menu/xonotic/playerlist.qc | 12 +- qcsrc/menu/xonotic/serverlist.qc | 17 +- qcsrc/menu/xonotic/textbox.qc | 90 +++++++++++ qcsrc/menu/xonotic/textbox.qh | 23 +++ qcsrc/menu/xonotic/util.qc | 13 ++ qcsrc/menu/xonotic/util.qh | 1 + qcsrc/server/scores.qc | 1 + qcsrc/server/world.qc | 11 ++ qcsrc/server/world.qh | 4 + xonotic-client.cfg | 3 + 27 files changed, 633 insertions(+), 150 deletions(-) create mode 100644 qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc create mode 100644 qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh create mode 100644 qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qc create mode 100644 qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh create mode 100644 qcsrc/menu/xonotic/dialog_termsofservice.qc create mode 100644 qcsrc/menu/xonotic/dialog_termsofservice.qh create mode 100644 qcsrc/menu/xonotic/textbox.qc create mode 100644 qcsrc/menu/xonotic/textbox.qh diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 2c43d12d9..feaa9f865 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -7,14 +7,15 @@ const int FRAGS_PLAYER_OUT_OF_GAME = -616; /////////////////////////// // cvar constants -const int CVAR_SAVE = 1; -const int CVAR_NOTIFY = 2; -const int CVAR_READONLY = 4; +const int CVAR_SAVE = BIT(0); +const int CVAR_NOTIFY = BIT(1); +const int CVAR_READONLY = BIT(2); // server flags -const int SERVERFLAG_ALLOW_FULLBRIGHT = 1; -const int SERVERFLAG_TEAMPLAY = 2; -const int SERVERFLAG_PLAYERSTATS = 4; +const int SERVERFLAG_ALLOW_FULLBRIGHT = BIT(0); +const int SERVERFLAG_TEAMPLAY = BIT(1); +const int SERVERFLAG_PLAYERSTATS = BIT(2); +const int SERVERFLAG_PLAYERSTATS_CUSTOM = BIT(3); const int SPECIES_HUMAN = 0; const int SPECIES_ROBOT_SOLID = 1; diff --git a/qcsrc/common/playerstats.qc b/qcsrc/common/playerstats.qc index 3d0ca1ee6..e3b1e8461 100644 --- a/qcsrc/common/playerstats.qc +++ b/qcsrc/common/playerstats.qc @@ -268,6 +268,10 @@ void PlayerStats_GameReport_Init() // initiated before InitGameplayMode so that PlayerStats_GameReport_DelayMapVote = true; serverflags |= SERVERFLAG_PLAYERSTATS; + if(autocvar_g_playerstats_gamereport_uri != cvar_defstring("g_playerstats_gamereport_uri")) + { + serverflags |= SERVERFLAG_PLAYERSTATS_CUSTOM; + } PlayerStats_GameReport_AddEvent(PLAYERSTATS_ALIVETIME); PlayerStats_GameReport_AddEvent(PLAYERSTATS_AVGLATENCY); diff --git a/qcsrc/lib/urllib.qh b/qcsrc/lib/urllib.qh index 8918ca0a2..639b5db73 100644 --- a/qcsrc/lib/urllib.qh +++ b/qcsrc/lib/urllib.qh @@ -7,6 +7,7 @@ const int URI_GET_IPBAN_END = 16; const int URI_GET_CURL = 17; const int URI_GET_CURL_END = 32; const int URI_GET_UPDATENOTIFICATION = 33; +const int URI_GET_TOS = 34; const int URI_GET_URLLIB = 128; const int URI_GET_URLLIB_END = 191; diff --git a/qcsrc/menu/xonotic/_mod.inc b/qcsrc/menu/xonotic/_mod.inc index 0f9a960c9..1c09f3586 100644 --- a/qcsrc/menu/xonotic/_mod.inc +++ b/qcsrc/menu/xonotic/_mod.inc @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -82,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/menu/xonotic/_mod.qh b/qcsrc/menu/xonotic/_mod.qh index 2bb4ccead..7c3ab9059 100644 --- a/qcsrc/menu/xonotic/_mod.qh +++ b/qcsrc/menu/xonotic/_mod.qh @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -82,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/menu/xonotic/dialog_firstrun.qc b/qcsrc/menu/xonotic/dialog_firstrun.qc index 6dc1cfcc0..c45256c52 100644 --- a/qcsrc/menu/xonotic/dialog_firstrun.qc +++ b/qcsrc/menu/xonotic/dialog_firstrun.qc @@ -8,6 +8,11 @@ #include "charmap.qh" #include "commandbutton.qh" +bool XonoticFirstRunDialog_shouldShow() +{ + return cvar_string("_cl_name") == cvar_defstring("_cl_name"); +} + float CheckFirstRunButton(entity me) { if(cvar_string("_cl_name") != cvar_defstring("_cl_name")) diff --git a/qcsrc/menu/xonotic/dialog_firstrun.qh b/qcsrc/menu/xonotic/dialog_firstrun.qh index 51a56bb6a..8952f009e 100644 --- a/qcsrc/menu/xonotic/dialog_firstrun.qh +++ b/qcsrc/menu/xonotic/dialog_firstrun.qh @@ -3,6 +3,7 @@ #include "rootdialog.qh" CLASS(XonoticFirstRunDialog, XonoticRootDialog) METHOD(XonoticFirstRunDialog, fill, void(entity)); + METHOD(XonoticFirstRunDialog, shouldShow, bool()); ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome")); ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN); ATTRIB(XonoticFirstRunDialog, intendedWidth, float, 0.7); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc index cf542f39c..f9ea1ef33 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc @@ -1,11 +1,15 @@ #include "dialog_multiplayer_join_serverinfo.qh" #include +#include "tabcontroller.qh" #include "serverlist.qh" #include "playerlist.qh" #include "inputbox.qh" #include "textlabel.qh" #include "button.qh" +#include "dialog_multiplayer_join_serverinfotab.qh" +#include "dialog_multiplayer_join_termsofservice.qh" + void XonoticServerInfoDialog_loadServerInfo(entity me, float i) { @@ -36,10 +40,10 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) // Now, fill in the strings // ========================== me.currentServerName = strzone(gethostcachestring(SLIST_FIELD_NAME, i)); - me.nameLabel.setText(me.nameLabel, me.currentServerName); + me.infoTab.nameLabel.setText(me.infoTab.nameLabel, me.currentServerName); me.currentServerCName = strzone(gethostcachestring(SLIST_FIELD_CNAME, i)); - me.cnameLabel.setText(me.cnameLabel, me.currentServerCName); + me.infoTab.cnameLabel.setText(me.infoTab.cnameLabel, me.currentServerCName); pure_available = false; pure_violations = -1; @@ -56,6 +60,7 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) freeslots = -1; sflags = -1; modname = ""; + bool ToSSpecified = false; for(int j = 2; j < m; ++j) { if(argv(j) == "") @@ -68,11 +73,37 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) pure_violations = stof(v); } else if(k == "S") + { freeslots = stof(v); + } else if(k == "F") + { sflags = stof(v); + } else if(k == "M") + { modname = v; + } + else if(k == "T") + { + ToSSpecified = true; + string downloadurl = v; + LOG_INFOF("SERVERTOS DOWNLOADURL: %s", downloadurl); + if (downloadurl == "INVALID") + { + me.ToSTab.textBox.setText(me.ToSTab.textBox, _("No Terms of Service specified")); + } + else + { + downloadurl = strreplace("|", ":", downloadurl); + me.ToSTab.loadToS(me.ToSTab, downloadurl); + } + } + } + + if (!ToSSpecified) + { + me.ToSTab.textBox.setText(me.ToSTab.textBox, _("No Terms of Service specified")); } #ifdef COMPAT_NO_MOD_IS_XONOTIC @@ -88,39 +119,39 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) if(j) { typestr = MapInfo_Type_ToText(j); } // only set it if we actually found it me.currentServerType = strzone(typestr); - me.typeLabel.setText(me.typeLabel, me.currentServerType); + me.infoTab.typeLabel.setText(me.infoTab.typeLabel, me.currentServerType); me.currentServerMap = strzone(gethostcachestring(SLIST_FIELD_MAP, i)); - me.mapLabel.setText(me.mapLabel, me.currentServerMap); + me.infoTab.mapLabel.setText(me.infoTab.mapLabel, me.currentServerMap); me.currentServerPlayers = strzone(gethostcachestring(SLIST_FIELD_PLAYERS, i)); - me.rawPlayerList.setPlayerList(me.rawPlayerList, me.currentServerPlayers); + me.infoTab.rawPlayerList.setPlayerList(me.infoTab.rawPlayerList, me.currentServerPlayers); numh = gethostcachenumber(SLIST_FIELD_NUMHUMANS, i); maxp = gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i); numb = gethostcachenumber(SLIST_FIELD_NUMBOTS, i); me.currentServerNumPlayers = strzone(sprintf("%d/%d", numh, maxp)); - me.numPlayersLabel.setText(me.numPlayersLabel, me.currentServerNumPlayers); + me.infoTab.numPlayersLabel.setText(me.infoTab.numPlayersLabel, me.currentServerNumPlayers); s = ftos(numb); me.currentServerNumBots = strzone(s); - me.numBotsLabel.setText(me.numBotsLabel, me.currentServerNumBots); + me.infoTab.numBotsLabel.setText(me.infoTab.numBotsLabel, me.currentServerNumBots); if(freeslots < 0) { freeslots = maxp - numh - numb; } s = ftos(freeslots); me.currentServerNumFreeSlots = strzone(s); - me.numFreeSlotsLabel.setText(me.numFreeSlotsLabel, me.currentServerNumFreeSlots); + me.infoTab.numFreeSlotsLabel.setText(me.infoTab.numFreeSlotsLabel, me.currentServerNumFreeSlots); me.currentServerMod = ((modname == "Xonotic") ? ZCTX(_("MOD^Default")) : modname); me.currentServerMod = strzone(me.currentServerMod); - me.modLabel.setText(me.modLabel, me.currentServerMod); + me.infoTab.modLabel.setText(me.infoTab.modLabel, me.currentServerMod); me.currentServerVersion = strzone(versionstr); - me.versionLabel.setText(me.versionLabel, me.currentServerVersion); + me.infoTab.versionLabel.setText(me.infoTab.versionLabel, me.currentServerVersion); me.currentServerPure = ((!pure_available) ? _("N/A") : (pure_violations == 0) ? _("Official") : sprintf(_("%d modified"), pure_violations)); me.currentServerPure = strzone(me.currentServerPure); - me.pureLabel.setText(me.pureLabel, me.currentServerPure); + me.infoTab.pureLabel.setText(me.infoTab.pureLabel, me.currentServerPure); s = crypto_getencryptlevel(me.currentServerCName); if(s == "") @@ -157,101 +188,34 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) me.currentServerEncrypt = _("Required (will encrypt)"); break; } - me.encryptLabel.setText(me.encryptLabel, me.currentServerEncrypt); - setZonedTooltip(me.encryptLabel, _("Use the `crypto_aeslevel` cvar to change your preferences"), string_null); + me.infoTab.encryptLabel.setText(me.infoTab.encryptLabel, me.currentServerEncrypt); + setZonedTooltip(me.infoTab.encryptLabel, _("Use the `crypto_aeslevel` cvar to change your preferences"), string_null); s = crypto_getidfp(me.currentServerCName); if (!s) { s = _("N/A"); } me.currentServerID = strzone(s); - me.idLabel.setText(me.idLabel, me.currentServerID); + me.infoTab.idLabel.setText(me.infoTab.idLabel, me.currentServerID); s = crypto_getkeyfp(me.currentServerCName); if (!s) { s = _("N/A"); } me.currentServerKey = strzone(s); - me.keyLabel.setText(me.keyLabel, me.currentServerKey); + me.infoTab.keyLabel.setText(me.infoTab.keyLabel, me.currentServerKey); + + me.currentServerStatsStatus = ((sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS)) ? ((sflags & SERVERFLAG_PLAYERSTATS_CUSTOM) ? _("custom stats server") : _("stats enabled")) : _("stats disabled")); + me.currentServerStatsStatus = strzone(me.currentServerStatsStatus); + me.infoTab.statsLabel.setText(me.infoTab.statsLabel, me.currentServerStatsStatus); } void XonoticServerInfoDialog_fill(entity me) { - entity e; + entity mc, e; + mc = makeXonoticTabController(me.rows - 2); me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Hostname:"))); - me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, "")); - e.colorL = SKINCOLOR_SERVERINFO_NAME; - e.allowCut = 1; - me.nameLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Address:"))); - me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, "")); - e.colorL = SKINCOLOR_SERVERINFO_IP; - e.allowCut = 1; - me.cnameLabel = e; + me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Status"), me.infoTab = makeXonoticServerInfoTab())); + me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Terms of Service"), me.ToSTab = makeXonoticServerToSTab())); me.TR(me); - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Gametype:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.typeLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Map:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.mapLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Mod:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.modLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Version:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.versionLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Settings:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.pureLabel = e; - - me.TR(me); - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Players:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.numPlayersLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Bots:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.numBotsLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Free slots:"))); - me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.numFreeSlotsLabel = e; - - me.gotoRC(me, me.rows - 5, 0); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Encryption:"))); - me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.encryptLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("ID:"))); - me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.keyLabel = e; - me.TR(me); - me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Key:"))); - me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); - e.allowCut = 1; - me.idLabel = e; - - me.gotoRC(me, 2, 2.2); me.setFirstColumn(me, me.currentColumn); - me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Players:"))); - me.TR(me); - me.TD(me, me.rows - 8, 4, e = makeXonoticPlayerList()); - me.rawPlayerList = e; + me.TD(me, me.rows - 2, me.columns, mc); me.gotoRC(me, me.rows - 1, 0); me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Close"), '0 0 0')); @@ -270,3 +234,4 @@ void Join_Click(entity btn, entity me) { localcmd("connect ", me.currentServerCName, "\n"); } + diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh index 68f5ab8ca..30a5453dd 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh @@ -2,44 +2,33 @@ #include "dialog.qh" CLASS(XonoticServerInfoDialog, XonoticDialog) - METHOD(XonoticServerInfoDialog, fill, void(entity)); METHOD(XonoticServerInfoDialog, loadServerInfo, void(entity, float)); - ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information")); - ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO); - ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.8); - ATTRIB(XonoticServerInfoDialog, rows, float, 18); - ATTRIB(XonoticServerInfoDialog, columns, float, 6.2); + METHOD(XonoticServerInfoDialog, fill, void(entity)); + ATTRIB(XonoticServerInfoDialog, title, string, _("Server Info")); + ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER); + ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.96); + ATTRIB(XonoticServerInfoDialog, rows, float, 19); + ATTRIB(XonoticServerInfoDialog, columns, float, 2); + ATTRIB(XonoticServerInfoDialog, infoTab, entity); + ATTRIB(XonoticServerInfoDialog, ToSTab, entity); - ATTRIB(XonoticServerInfoDialog, currentServerName, string); - ATTRIB(XonoticServerInfoDialog, currentServerCName, string); - ATTRIB(XonoticServerInfoDialog, currentServerType, string); - ATTRIB(XonoticServerInfoDialog, currentServerMap, string); - ATTRIB(XonoticServerInfoDialog, currentServerPlayers, string); - ATTRIB(XonoticServerInfoDialog, currentServerNumPlayers, string); - ATTRIB(XonoticServerInfoDialog, currentServerNumBots, string); - ATTRIB(XonoticServerInfoDialog, currentServerNumFreeSlots, string); - ATTRIB(XonoticServerInfoDialog, currentServerMod, string); - ATTRIB(XonoticServerInfoDialog, currentServerVersion, string); - ATTRIB(XonoticServerInfoDialog, currentServerKey, string); - ATTRIB(XonoticServerInfoDialog, currentServerID, string); - ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string); - ATTRIB(XonoticServerInfoDialog, currentServerPure, string); + ATTRIB(XonoticServerInfoTab, currentServerName, string); + ATTRIB(XonoticServerInfoTab, currentServerCName, string); + ATTRIB(XonoticServerInfoTab, currentServerType, string); + ATTRIB(XonoticServerInfoTab, currentServerMap, string); + ATTRIB(XonoticServerInfoTab, currentServerPlayers, string); + ATTRIB(XonoticServerInfoTab, currentServerNumPlayers, string); + ATTRIB(XonoticServerInfoTab, currentServerNumBots, string); + ATTRIB(XonoticServerInfoTab, currentServerNumFreeSlots, string); + ATTRIB(XonoticServerInfoTab, currentServerMod, string); + ATTRIB(XonoticServerInfoTab, currentServerVersion, string); + ATTRIB(XonoticServerInfoTab, currentServerKey, string); + ATTRIB(XonoticServerInfoTab, currentServerID, string); + ATTRIB(XonoticServerInfoTab, currentServerEncrypt, string); + ATTRIB(XonoticServerInfoTab, currentServerPure, string); + ATTRIB(XonoticServerInfoTab, currentServerStatsStatus, string); - ATTRIB(XonoticServerInfoDialog, nameLabel, entity); - ATTRIB(XonoticServerInfoDialog, cnameLabel, entity); - ATTRIB(XonoticServerInfoDialog, typeLabel, entity); - ATTRIB(XonoticServerInfoDialog, mapLabel, entity); - ATTRIB(XonoticServerInfoDialog, rawPlayerList, entity); - ATTRIB(XonoticServerInfoDialog, numPlayersLabel, entity); - ATTRIB(XonoticServerInfoDialog, numBotsLabel, entity); - ATTRIB(XonoticServerInfoDialog, numFreeSlotsLabel, entity); - ATTRIB(XonoticServerInfoDialog, modLabel, entity); - ATTRIB(XonoticServerInfoDialog, versionLabel, entity); - ATTRIB(XonoticServerInfoDialog, keyLabel, entity); - ATTRIB(XonoticServerInfoDialog, idLabel, entity); - ATTRIB(XonoticServerInfoDialog, encryptLabel, entity); - ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity); - ATTRIB(XonoticServerInfoDialog, pureLabel, entity); ENDCLASS(XonoticServerInfoDialog) void Join_Click(entity btn, entity me); + diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc new file mode 100644 index 000000000..5b2dc05ab --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc @@ -0,0 +1,107 @@ +#include "dialog_multiplayer_join_serverinfo.qh" +#include "dialog_multiplayer_join_serverinfotab.qh" +#include + +#include "serverlist.qh" +#include "playerlist.qh" +#include "inputbox.qh" +#include "textlabel.qh" +#include "button.qh" + + +entity makeXonoticServerInfoTab() +{ + entity me; + me = NEW(XonoticServerInfoTab); + me.configureDialog(me); + return me; +} + +void XonoticServerInfoTab_fill(entity me) +{ + entity e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Hostname:"))); + me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, "")); + e.colorL = SKINCOLOR_SERVERINFO_NAME; + e.allowCut = 1; + me.nameLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Address:"))); + me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, "")); + e.colorL = SKINCOLOR_SERVERINFO_IP; + e.allowCut = 1; + me.cnameLabel = e; + + me.TR(me); + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Gametype:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.typeLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Map:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.mapLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Mod:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.modLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Version:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.versionLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Settings:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.pureLabel = e; + + me.TR(me); + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Players:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.numPlayersLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Bots:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.numBotsLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Free slots:"))); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.numFreeSlotsLabel = e; + + me.gotoRC(me, me.rows - 5, 0); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Encryption:"))); + me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.encryptLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("ID:"))); + me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.keyLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Key:"))); + me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.idLabel = e; + me.TR(me); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Stats:"))); + me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.statsLabel = e; + + me.gotoRC(me, 2, 2.2); me.setFirstColumn(me, me.currentColumn); + me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Players:"))); + me.TR(me); + me.TD(me, me.rows - 8, 4, e = makeXonoticPlayerList()); + me.rawPlayerList = e; +} + diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh new file mode 100644 index 000000000..ed3515f99 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh @@ -0,0 +1,30 @@ +#pragma once + +#include "tab.qh" +CLASS(XonoticServerInfoTab, XonoticTab) + METHOD(XonoticServerInfoTab, fill, void(entity)); + ATTRIB(XonoticServerInfoTab, title, string, _("Server Information")); + ATTRIB(XonoticServerInfoTab, color, vector, SKINCOLOR_DIALOG_SERVERINFO); + ATTRIB(XonoticServerInfoTab, intendedWidth, float, 0.8); + ATTRIB(XonoticServerInfoTab, rows, float, 17); + ATTRIB(XonoticServerInfoTab, columns, float, 6.2); + + ATTRIB(XonoticServerInfoTab, nameLabel, entity); + ATTRIB(XonoticServerInfoTab, cnameLabel, entity); + ATTRIB(XonoticServerInfoTab, typeLabel, entity); + ATTRIB(XonoticServerInfoTab, mapLabel, entity); + ATTRIB(XonoticServerInfoTab, rawPlayerList, entity); + ATTRIB(XonoticServerInfoTab, numPlayersLabel, entity); + ATTRIB(XonoticServerInfoTab, numBotsLabel, entity); + ATTRIB(XonoticServerInfoTab, numFreeSlotsLabel, entity); + ATTRIB(XonoticServerInfoTab, modLabel, entity); + ATTRIB(XonoticServerInfoTab, versionLabel, entity); + ATTRIB(XonoticServerInfoTab, keyLabel, entity); + ATTRIB(XonoticServerInfoTab, idLabel, entity); + ATTRIB(XonoticServerInfoTab, encryptLabel, entity); + ATTRIB(XonoticServerInfoTab, canConnectLabel, entity); + ATTRIB(XonoticServerInfoTab, pureLabel, entity); + ATTRIB(XonoticServerInfoTab, statsLabel, entity); +ENDCLASS(XonoticServerInfoTab) +entity makeXonoticServerInfoTab(); + diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qc b/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qc new file mode 100644 index 000000000..81d089785 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qc @@ -0,0 +1,62 @@ +#include "dialog_multiplayer_join_termsofservice.qh" + +#include "textbox.qh" +#include + + +entity makeXonoticServerToSTab() +{ + entity me; + me = NEW(XonoticServerToSTab); + me.configureDialog(me); + return me; +} + +void XonoticServerToSTab_loadToS(entity me, string downloadurl) +{ + url_single_fopen(downloadurl, FILE_READ, AdditionalServerInfo_OnGet, me); +} + +void XonoticServerToSTab_fill(entity me) +{ + entity e; + me.TR(me); + me.TD(me, me.rows, me.columns, e = makeXonoticTextBox()); + me.textBox = e; +} + +void AdditionalServerInfo_OnGet(entity fh, entity me, int status) +{ + switch (status) { + case URL_READY_CLOSED: + { + break; + } + case URL_READY_ERROR: + { + me.text = strzone("Error reading ToS"); + me.textBox.setText(me.textBox, me.text); + break; + } + case URL_READY_CANREAD: + { + strfree(me.text); + string temp = ""; + for (string s; (s = url_fgets(fh)); ) + { + if (temp != "") + temp = strcat(temp, "\n", s); + else + temp = s; + } + url_fclose(fh); + me.text = strzone(temp); + me.textBox.setText(me.textBox, me.text); + break; + } + default: + { + break; + } + } +} diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh b/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh new file mode 100644 index 000000000..ebc2d867e --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh @@ -0,0 +1,18 @@ +#pragma once + +#include "tab.qh" +CLASS(XonoticServerToSTab, XonoticTab) + METHOD(XonoticServerToSTab, fill, void(entity)); + METHOD(XonoticServerToSTab, loadToS, void(entity, string)); + ATTRIB(XonoticServerToSTab, title, string, _("Terms of Service")); + ATTRIB(XonoticServerToSTab, color, vector, SKINCOLOR_DIALOG_SERVERINFO); + ATTRIB(XonoticServerToSTab, intendedWidth, float, 0.8); + ATTRIB(XonoticServerToSTab, rows, float, 17); + ATTRIB(XonoticServerToSTab, columns, float, 6.2); + + ATTRIB(XonoticServerToSTab, text, string); + ATTRIB(XonoticServerToSTab, textBox, entity); +ENDCLASS(XonoticServerToSTab) +entity makeXonoticServerToSTab(); + +void AdditionalServerInfo_OnGet(entity fh, entity pass, int status); diff --git a/qcsrc/menu/xonotic/dialog_termsofservice.qc b/qcsrc/menu/xonotic/dialog_termsofservice.qc new file mode 100644 index 000000000..39ffaa43c --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_termsofservice.qc @@ -0,0 +1,102 @@ +#include "dialog_termsofservice.qh" + +#include "../menu.qh" +#include "mainwindow.qh" +#include "dialog_firstrun.qh" +#include "textbox.qh" +#include "textlabel.qh" +#include "button.qh" +#include "util.qh" + +void Close_Clicked(entity btn, entity me) +{ + LOG_INFOF("Accepted ToS version %d", _Nex_ExtResponseSystem_NewToS); + cvar_set("_termsofservice_accepted", ftos(_Nex_ExtResponseSystem_NewToS)); + localcmd("saveconfig\n"); + if (main.firstRunDialog.shouldShow()) + main.firstDraw = true; + Dialog_Close(btn, me); +} + +void DontAccept_Clicked(entity btn, entity me) +{ + localcmd("quit\n"); +} + +void XonoticToSDialog_loadXonoticToS(entity me) +{ + url_single_fopen(termsofservice_url, FILE_READ, XonoticToS_OnGet, me); +} + +void XonoticToS_OnGet(entity fh, entity me, int status) +{ + switch (status) { + case URL_READY_CLOSED: + { + break; + } + case URL_READY_ERROR: + { + me.text = strzone("Error reading ToS"); + me.textBox.setText(me.textBox, me.text); + break; + } + case URL_READY_CANREAD: + { + strfree(me.text); + string temp = ""; + for (string s; (s = url_fgets(fh)); ) + { + if (temp != "") + temp = strcat(temp, "\n", s); + else + temp = s; + } + url_fclose(fh); + me.text = strzone(temp); + me.textBox.setText(me.textBox, me.text); + break; + } + default: + { + break; + } + } +} + +bool XonoticToSDialog_shouldShow() +{ + return (_Nex_ExtResponseSystem_NewToS && _Nex_ExtResponseSystem_NewToS > autocvar__termsofservice_accepted); +} + +void XonoticToSDialog_fill(entity me) +{ + entity e; + string subtitle; + + if (autocvar__termsofservice_accepted > 0) + subtitle = _("Terms of Service have been updated. Please read them before continuing:"); + else + subtitle = _("Welcome to Xonotic! Please read the following Terms of Service:"); + + me.TR(me); + me.TD(me, 1, 5, e = makeXonoticTextLabel(0, subtitle)); + e.allowWrap = 1; + + me.TR(me); + me.TR(me); + me.TD(me, me.rows - 4, me.columns, me.textBox = makeXonoticTextBox()); + me.loadXonoticToS(me); + + me.TR(me); + me.gotoRC(me, me.rows - 1, 0); + + me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Accept"), '0 1 0')); + e.onClick = Close_Clicked; + e.onClickEntity = me; + + me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Don't accept (quit the game)"), '1 0 0')); + e.onClick = DontAccept_Clicked; + e.onClickEntity = me; +} + diff --git a/qcsrc/menu/xonotic/dialog_termsofservice.qh b/qcsrc/menu/xonotic/dialog_termsofservice.qh new file mode 100644 index 000000000..9231f3063 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_termsofservice.qh @@ -0,0 +1,24 @@ +#pragma once + +int autocvar__termsofservice_accepted; +const string termsofservice_url = "http://update.xonotic.org/tos.txt"; + +#include "rootdialog.qh" +CLASS(XonoticToSDialog, XonoticRootDialog) + METHOD(XonoticToSDialog, shouldShow, bool()); + METHOD(XonoticToSDialog, fill, void(entity)); + METHOD(XonoticToSDialog, loadXonoticToS, void(entity)); + ATTRIB(XonoticToSDialog, title, string, _("Terms of Service")); + ATTRIB(XonoticToSDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN); + ATTRIB(XonoticToSDialog, intendedWidth, float, 0.8); + ATTRIB(XonoticToSDialog, rows, float, 16); + ATTRIB(XonoticToSDialog, columns, float, 6.2); + ATTRIB(XonoticToSDialog, name, string, "TermsOfService"); + + ATTRIB(XonoticToSDialog, text, string); + ATTRIB(XonoticToSDialog, textBox, entity); + + ATTRIB(XonoticToSDialog, closable, float, 0); +ENDCLASS(XonoticToSDialog) + +void XonoticToS_OnGet(entity fh, entity me, int status); diff --git a/qcsrc/menu/xonotic/mainwindow.qc b/qcsrc/menu/xonotic/mainwindow.qc index 89a61fb0d..4aa974835 100644 --- a/qcsrc/menu/xonotic/mainwindow.qc +++ b/qcsrc/menu/xonotic/mainwindow.qc @@ -4,6 +4,7 @@ #include "nexposee.qh" #include "inputbox.qh" +#include "dialog_termsofservice.qh" #include "dialog_firstrun.qh" #include "dialog_hudsetup_exit.qh" #include "dialog_hudpanel_notification.qh" @@ -58,10 +59,13 @@ void MainWindow_draw(entity me) { SUPER(MainWindow).draw(me); - if(me.dialogToShow) - { - DialogOpenButton_Click_withCoords(NULL, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight); - me.dialogToShow = NULL; + if (me.firstDraw) { + if (me.ToSDialog.shouldShow()) + DialogOpenButton_Click_withCoords(NULL, me.ToSDialog, '0 0 0', eX * conwidth + eY * conheight); + else if(me.firstRunDialog.shouldShow()) + DialogOpenButton_Click_withCoords(NULL, me.firstRunDialog, '0 0 0', eX * conwidth + eY * conheight); + + me.firstDraw = false; } //------------------------------------- @@ -104,6 +108,11 @@ void MainWindow_configureMainWindow(entity me) { entity n, i; + // terms of service dialog + me.ToSDialog = i = NEW(XonoticToSDialog); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + // dialog run upon startup me.firstRunDialog = i = NEW(XonoticFirstRunDialog); i.configureDialog(i); @@ -281,7 +290,7 @@ void MainWindow_configureMainWindow(entity me) // main dialogs/windows me.mainNexposee = n = NEW(XonoticNexposee); - + /* if(checkextension("DP_GECKO_SUPPORT")) { @@ -291,7 +300,7 @@ void MainWindow_configureMainWindow(entity me) n.setNexposee(n, i, '0.1 0.1 0', SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); } */ - + i = NEW(XonoticSingleplayerDialog); i.configureDialog(i); n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); @@ -332,7 +341,4 @@ void MainWindow_configureMainWindow(entity me) me.initializeDialog(me, n); me.disconnectDialogVisibility = 1; - - if(cvar_string("_cl_name") == cvar_defstring("_cl_name")) - me.dialogToShow = me.firstRunDialog; } diff --git a/qcsrc/menu/xonotic/mainwindow.qh b/qcsrc/menu/xonotic/mainwindow.qh index 1e8afa4a3..82e126a9f 100644 --- a/qcsrc/menu/xonotic/mainwindow.qh +++ b/qcsrc/menu/xonotic/mainwindow.qh @@ -5,6 +5,7 @@ CLASS(MainWindow, ModalController) METHOD(MainWindow, configureMainWindow, void(entity)); METHOD(MainWindow, draw, void(entity)); + ATTRIB(MainWindow, ToSDialog, entity); ATTRIB(MainWindow, firstRunDialog, entity); ATTRIB(MainWindow, advancedDialog, entity); ATTRIB(MainWindow, mutatorsDialog, entity); @@ -20,7 +21,7 @@ CLASS(MainWindow, ModalController) ATTRIB(MainWindow, languageWarningDialog, entity); ATTRIB(MainWindow, mainNexposee, entity); ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND); - ATTRIB(MainWindow, dialogToShow, entity); + ATTRIB(MainWindow, firstDraw, bool, true); ATTRIB(MainWindow, demostartconfirmDialog, entity); ATTRIB(MainWindow, demotimeconfirmDialog, entity); ATTRIB(MainWindow, resetDialog, entity); diff --git a/qcsrc/menu/xonotic/playerlist.qc b/qcsrc/menu/xonotic/playerlist.qc index e90eef23d..1edc5b840 100644 --- a/qcsrc/menu/xonotic/playerlist.qc +++ b/qcsrc/menu/xonotic/playerlist.qc @@ -2,11 +2,11 @@ .float realUpperMargin2; -const float PLAYERPARM_SCORE = 0; -const float PLAYERPARM_PING = 1; -const float PLAYERPARM_TEAM = 2; -const float PLAYERPARM_NAME = 3; -const float PLAYERPARM_COUNT = 4; +const int PLAYERPARM_SCORE = 0; +const int PLAYERPARM_PING = 1; +const int PLAYERPARM_TEAM = 2; +const int PLAYERPARM_NAME = 3; +const int PLAYERPARM_COUNT = 4; entity makeXonoticPlayerList() { @@ -33,7 +33,7 @@ void XonoticPlayerList_setPlayerList(entity me, string plist) s = bufstr_get(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME); n = tokenize_console(s); - if(n == 4) + if(n == PLAYERPARM_COUNT) { bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666 bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING, argv(1)); // 100 diff --git a/qcsrc/menu/xonotic/serverlist.qc b/qcsrc/menu/xonotic/serverlist.qc index e20a13a8e..38678a868 100644 --- a/qcsrc/menu/xonotic/serverlist.qc +++ b/qcsrc/menu/xonotic/serverlist.qc @@ -1036,7 +1036,20 @@ void XonoticServerList_drawListBoxItem(entity me, int i, vector absSize, bool is // Stats if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS)) - draw_Picture(iconPos, "icon_stats1", iconSize, '1 1 1', 1); + { + if (sflags & SERVERFLAG_PLAYERSTATS_CUSTOM) + { + draw_Picture(iconPos, "icon_mod_", iconSize, '1 1 1', 1); // TODO: icon + } + else + { + draw_Picture(iconPos, "icon_stats1", iconSize, '1 1 1', 1); + } + } + else + { + draw_Picture(iconPos, "icon_mod_jeff", iconSize, '1 1 1', 1); // TODO: icon + } if(isFocused && me.mouseOverIcons && !me.tooltip) { @@ -1048,7 +1061,7 @@ void XonoticServerList_drawListBoxItem(entity me, int i, vector absSize, bool is if(pure_available) t = strcat(t, sprintf(" (%s)", (pure) ? _("official settings") : _("modified settings"))); t = strcat(t, ", "); - t = strcat(t, ((sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS)) ? _("stats enabled") : _("stats disabled"))); + t = strcat(t, ((sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS)) ? ((sflags & SERVERFLAG_PLAYERSTATS_CUSTOM) ? _("custom stats server") : _("stats enabled")) : _("stats disabled"))); setZonedTooltip(me, t, string_null); } // -------------- diff --git a/qcsrc/menu/xonotic/textbox.qc b/qcsrc/menu/xonotic/textbox.qc new file mode 100644 index 000000000..1027d0c9e --- /dev/null +++ b/qcsrc/menu/xonotic/textbox.qc @@ -0,0 +1,90 @@ +#include "textbox.qh" +#include "../item/label.qh" + +entity makeXonoticTextBox() +{ + entity me; + me = NEW(XonoticTextBox); + me.configureXonoticListBox(me); + return me; +} + +void XonoticTextBox_destroy(entity me) +{ + if (me.stringList >= 0) + { + buf_del(me.stringList); + me.stringList = -1; + } +} + +void XonoticTextBox_setText(entity me, string text) +{ + if (me.stringList >= 0) + { + buf_del(me.stringList); + me.stringList = -1; + } + + int buf; + int line = 0; + + string t; + + buf = buf_create(); + for (int i = 0, n = tokenizebyseparator(text, "\n"); i < n; ++i) + { + t = substring(argv(i), 0, -1); + getWrappedLine_remaining = t; + while (getWrappedLine_remaining) + { + t = getWrappedLine(1, me.realFontSize, draw_TextWidth_WithColors); + bufstr_set(buf, line, t); + line++; + } + } + + me.stringList = buf; + me.nItems = line+1; +} + +string XonoticTextBox_getTextBoxLine(entity me, int i) +{ + if (me.stringList >= 0) + { + return bufstr_get(me.stringList, i); + } + return string_null; +} + +// mostly copied from playerlist +// FIXME: is this really needed +void XonoticTextBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) +{ + me.itemAbsSize = '0 0 0'; + SUPER(XonoticTextBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize); + + me.itemAbsSize.y = absSize.y * me.itemHeight; + me.itemAbsSize.x = absSize.x * (1 - me.controlWidth); + me.realFontSize.y = me.fontSize / me.itemAbsSize.y; + me.realFontSize.x = me.fontSize / me.itemAbsSize.x; + string temp = string_null; + for (int i = 0; i < me.nItems; ++i) + { + if (!temp) + { + temp = me.getTextBoxLine(me, i); + } + else + { + temp = strcat(temp, "\n", me.getTextBoxLine(me, i)); + } + } + me.setText(me, temp); +} + +void XonoticTextBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused) +{ + string s = me.getTextBoxLine(me, i); + draw_Text(vec2(0, 0), s, me.realFontSize, me.colorL, me.alpha, true); +} diff --git a/qcsrc/menu/xonotic/textbox.qh b/qcsrc/menu/xonotic/textbox.qh new file mode 100644 index 000000000..b27481671 --- /dev/null +++ b/qcsrc/menu/xonotic/textbox.qh @@ -0,0 +1,23 @@ +#pragma once + +#include "listbox.qh" + +// slightly hacky multiline textbox with scrollbar +CLASS(XonoticTextBox, XonoticListBox) + METHOD(XonoticTextBox, destroy, void(entity)); + ATTRIB(XonoticTextBox, rowsPerItem, float, 1); + METHOD(XonoticTextBox, resizeNotify, void(entity, vector, vector, vector, vector)); + METHOD(XonoticTextBox, drawListBoxItem, void(entity, int, vector, bool, bool)); + ATTRIB(XonoticTextBox, allowFocusSound, float, 0); + ATTRIB(XonoticTextBox, alpha, float, SKINALPHA_TEXT); + ATTRIB(XonoticTextBox, fontSize, float, SKINFONTSIZE_NORMAL); + ATTRIB(XonoticTextBox, realFontSize, vector, '0 0 0'); + ATTRIB(XonoticTextBox, itemAbsSize, vector, '0 0 0'); + METHOD(XonoticTextBox, setText, void(entity, string)); + METHOD(XonoticTextBox, getTextBoxLine, string(entity, int)); + ATTRIB(XonoticTextBox, nItems, int, 0); + ATTRIB(XonoticTextBox, stringList, int, -1); + ATTRIB(XonoticTextBox, selectionDoesntMatter, bool, true); +ENDCLASS(XonoticTextBox) +entity makeXonoticTextBox(); + diff --git a/qcsrc/menu/xonotic/util.qc b/qcsrc/menu/xonotic/util.qc index e77049d20..06139566d 100644 --- a/qcsrc/menu/xonotic/util.qc +++ b/qcsrc/menu/xonotic/util.qc @@ -352,6 +352,7 @@ void UpdateNotification_URI_Get_Callback(float id, float status, string data) string s; string un_version = ""; + string un_tosversion = ""; string un_download = ""; string un_url = ""; string un_bannedservers = ""; @@ -372,6 +373,11 @@ void UpdateNotification_URI_Get_Callback(float id, float status, string data) un_version = s; break; } + case "T": + { + un_tosversion = s; + break; + } case "C": { un_compatexpire = s; @@ -431,6 +437,12 @@ void UpdateNotification_URI_Get_Callback(float id, float status, string data) } } } + + if(un_tosversion != "") + { + _Nex_ExtResponseSystem_NewToS = stof(un_tosversion); + LOG_INFOF("Latest ToS version is %d", _Nex_ExtResponseSystem_NewToS); + } if(un_bannedservers != "") { @@ -582,6 +594,7 @@ void preMenuDraw() draw_CenterText(mid - 1 * line, l1, fs, '1 0 0', 1, 0); draw_CenterText(mid - 0 * line, l2, fs, '0 0 1', 1, 0); } + if (!campaign_name_previous) campaign_name_previous = strzone(strcat(campaign_name, "x")); // force unequal if(campaign_name == campaign_name_previous) diff --git a/qcsrc/menu/xonotic/util.qh b/qcsrc/menu/xonotic/util.qh index f5bd636d8..9e90c7776 100644 --- a/qcsrc/menu/xonotic/util.qh +++ b/qcsrc/menu/xonotic/util.qh @@ -47,5 +47,6 @@ string _Nex_ExtResponseSystem_PromotedServers; float _Nex_ExtResponseSystem_PromotedServersNeedsRefresh; string _Nex_ExtResponseSystem_RecommendedServers; float _Nex_ExtResponseSystem_RecommendedServersNeedsRefresh; +float _Nex_ExtResponseSystem_NewToS; void CheckSendCvars(entity me, string cvarnamestring); diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index 7e1bfd1e5..07c400f5d 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -434,6 +434,7 @@ void WinningConditionHelper(entity this) s = strcat(s, ":P", ftos(cvar_purechanges_count)); s = strcat(s, ":S", ftos(nJoinAllowed(this, NULL))); s = strcat(s, ":F", ftos(serverflags)); + s = strcat(s, ":T", sv_termsofservice_url_escaped); s = strcat(s, ":M", modname); s = strcat(s, "::", GetPlayerScoreString(NULL, (fullstatus ? 1 : 2))); diff --git a/qcsrc/server/world.qc b/qcsrc/server/world.qc index e2a44d2c8..51093d51b 100644 --- a/qcsrc/server/world.qc +++ b/qcsrc/server/world.qc @@ -689,6 +689,15 @@ spawnfunc(worldspawn) { server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated"))); + if (autocvar_sv_termsofservice_url && autocvar_sv_termsofservice_url != "") + { + strcpy(sv_termsofservice_url_escaped, strreplace(":", "|", autocvar_sv_termsofservice_url)); + } + else + { + strcpy(sv_termsofservice_url_escaped, "INVALID"); + } + bool wantrestart = false; { if (!server_is_dedicated) @@ -2430,6 +2439,8 @@ void Shutdown() WeaponStats_Shutdown(); MapInfo_Shutdown(); + + strfree(sv_termsofservice_url_escaped); } else if(world_initialized == 0) { diff --git a/qcsrc/server/world.qh b/qcsrc/server/world.qh index 3f6b9b6d2..299c88535 100644 --- a/qcsrc/server/world.qh +++ b/qcsrc/server/world.qh @@ -47,6 +47,10 @@ string gamemode_name; string record_type; +string autocvar_sv_termsofservice_url; +// only escape the terms of service url on map change +string sv_termsofservice_url_escaped; + string clientstuff; string matchid; diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 8ade6794e..c57770518 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -842,6 +842,9 @@ seta cl_allow_uid2name -1 "-1 = ask if the player wants to disable/enable this f seta cl_allow_uidtracking 1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid tracking (allows associating your data with your player ID)" seta cl_allow_uidranking 1 "0 = disable, 1 = enable uid ranking (allows statistics like elo to rank you in leaderboards)" +// terms of service +seta _termsofservice_accepted 0 + // polygonoffset for submodel SUCKS SUCKS SUCKS (only a hack for quake1, we don't need that) r_polygonoffset_submodel_offset 0 r_polygonoffset_submodel_factor 0 -- 2.39.2