]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Add Terms of Service Popup and server-specific Terms of Service tab
authorFreddy <schro.sb@gmail.com>
Thu, 3 Feb 2022 14:03:21 +0000 (14:03 +0000)
committerterencehill <piuntn@gmail.com>
Thu, 3 Feb 2022 14:03:21 +0000 (14:03 +0000)
Author Freddy, contributed by z411, minor contributions by Mario, LegendaryGuard and terencehill

27 files changed:
qcsrc/common/constants.qh
qcsrc/common/playerstats.qc
qcsrc/lib/urllib.qh
qcsrc/menu/xonotic/_mod.inc
qcsrc/menu/xonotic/_mod.qh
qcsrc/menu/xonotic/dialog_firstrun.qc
qcsrc/menu/xonotic/dialog_firstrun.qh
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_termsofservice.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_termsofservice.qh [new file with mode: 0644]
qcsrc/menu/xonotic/mainwindow.qc
qcsrc/menu/xonotic/mainwindow.qh
qcsrc/menu/xonotic/playerlist.qc
qcsrc/menu/xonotic/serverlist.qc
qcsrc/menu/xonotic/textbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/textbox.qh [new file with mode: 0644]
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/server/scores.qc
qcsrc/server/world.qc
qcsrc/server/world.qh
xonotic-client.cfg

index 2c43d12d98ec3a178ef470fa0d09b962938e078e..feaa9f8651ea47e3251ae867f5c88a335718edc0 100644 (file)
@@ -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;
index 3d0ca1ee6d6154f731f4eff2884522d7b5091552..e3b1e8461c77e796ff70ddf98f5f8903ea3406cb 100644 (file)
@@ -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);
index 8918ca0a2a695df6ade44e96df9837b271adc3a4..639b5db73e0615f6caa49b1cc494892faf38ab0f 100644 (file)
@@ -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;
 
index 0f9a960c92f657e0dc00ba00ff1ea3a26bdb10bd..1c09f35866a80a4178f06c39f94a7c77573d0431 100644 (file)
@@ -49,6 +49,8 @@
 #include <menu/xonotic/dialog_multiplayer_create_mutators.qc>
 #include <menu/xonotic/dialog_multiplayer_join.qc>
 #include <menu/xonotic/dialog_multiplayer_join_serverinfo.qc>
+#include <menu/xonotic/dialog_multiplayer_join_serverinfotab.qc>
+#include <menu/xonotic/dialog_multiplayer_join_termsofservice.qc>
 #include <menu/xonotic/dialog_multiplayer_media.qc>
 #include <menu/xonotic/dialog_multiplayer_media_demo.qc>
 #include <menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc>
@@ -82,6 +84,7 @@
 #include <menu/xonotic/dialog_singleplayer.qc>
 #include <menu/xonotic/dialog_singleplayer_winner.qc>
 #include <menu/xonotic/dialog_teamselect.qc>
+#include <menu/xonotic/dialog_termsofservice.qc>
 #include <menu/xonotic/dialog_uid2name.qc>
 #include <menu/xonotic/gametypelist.qc>
 #include <menu/xonotic/hudskinlist.qc>
 #include <menu/xonotic/statslist.qc>
 #include <menu/xonotic/tab.qc>
 #include <menu/xonotic/tabcontroller.qc>
+#include <menu/xonotic/textbox.qc>
 #include <menu/xonotic/textlabel.qc>
 #include <menu/xonotic/textslider.qc>
 #include <menu/xonotic/util.qc>
index 2bb4ccead24a71d6df581c6db654e49acd47cb7e..7c3ab9059b5fa6f57c1208f40f9a840d920b2a6d 100644 (file)
@@ -49,6 +49,8 @@
 #include <menu/xonotic/dialog_multiplayer_create_mutators.qh>
 #include <menu/xonotic/dialog_multiplayer_join.qh>
 #include <menu/xonotic/dialog_multiplayer_join_serverinfo.qh>
+#include <menu/xonotic/dialog_multiplayer_join_serverinfotab.qh>
+#include <menu/xonotic/dialog_multiplayer_join_termsofservice.qh>
 #include <menu/xonotic/dialog_multiplayer_media.qh>
 #include <menu/xonotic/dialog_multiplayer_media_demo.qh>
 #include <menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh>
@@ -82,6 +84,7 @@
 #include <menu/xonotic/dialog_singleplayer.qh>
 #include <menu/xonotic/dialog_singleplayer_winner.qh>
 #include <menu/xonotic/dialog_teamselect.qh>
+#include <menu/xonotic/dialog_termsofservice.qh>
 #include <menu/xonotic/dialog_uid2name.qh>
 #include <menu/xonotic/gametypelist.qh>
 #include <menu/xonotic/hudskinlist.qh>
 #include <menu/xonotic/statslist.qh>
 #include <menu/xonotic/tab.qh>
 #include <menu/xonotic/tabcontroller.qh>
+#include <menu/xonotic/textbox.qh>
 #include <menu/xonotic/textlabel.qh>
 #include <menu/xonotic/textslider.qh>
 #include <menu/xonotic/util.qh>
index 6dc1cfcc09c0415baaaefc702e5e65cbf24ad4b2..c45256c525621e59e2eeb901d6efd3dcca8c1e7e 100644 (file)
@@ -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"))
index 51a56bb6aa66a7e3d9b1411d5351015a1904c11f..8952f009eaecc91fd01347856e5d0aec860346c0 100644 (file)
@@ -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);
index cf542f39c8f47d0d6120c6ef1e56336a07676e90..f9ea1ef33e8ff2cc5fb139190dbd48eb80ec493d 100644 (file)
@@ -1,11 +1,15 @@
 #include "dialog_multiplayer_join_serverinfo.qh"
 #include <common/mapinfo.qh>
 
+#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");
 }
+
index 68f5ab8ca0c08cc95084715202fbb9ec5e442f36..30a5453dd111253030786aa1a6f473a0cae2d1d1 100644 (file)
@@ -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 (file)
index 0000000..5b2dc05
--- /dev/null
@@ -0,0 +1,107 @@
+#include "dialog_multiplayer_join_serverinfo.qh"
+#include "dialog_multiplayer_join_serverinfotab.qh"
+#include <common/mapinfo.qh>
+
+#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 (file)
index 0000000..ed3515f
--- /dev/null
@@ -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 (file)
index 0000000..81d0897
--- /dev/null
@@ -0,0 +1,62 @@
+#include "dialog_multiplayer_join_termsofservice.qh"
+
+#include "textbox.qh"
+#include <lib/urllib.qh>
+
+
+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 (file)
index 0000000..ebc2d86
--- /dev/null
@@ -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 (file)
index 0000000..39ffaa4
--- /dev/null
@@ -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 (file)
index 0000000..9231f30
--- /dev/null
@@ -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);
index 89a61fb0d89d2fff669177c4245b5c738d0aad4c..4aa974835a58da15959f2d79e5b7be34d9324e0d 100644 (file)
@@ -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;
 }
index 1e8afa4a39b1b3344ee7c4990247cdec9acd120e..82e126a9f0f41025c7cf7c7ae725d0d51020abe4 100644 (file)
@@ -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);
index e90eef23d3a11d2c63a2aa33798f49522508a396..1edc5b8400c8cc6347f5916125ebc34c850e5e0d 100644 (file)
@@ -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
index e20a13a8ee58a95ca3fe06b899a2d87409375ef5..38678a8687155ae40159b7694584d574feb957bd 100644 (file)
@@ -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 (file)
index 0000000..1027d0c
--- /dev/null
@@ -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 (file)
index 0000000..b274816
--- /dev/null
@@ -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();
+
index e77049d200153e9c2f15fb0ca097edd1c1649fe3..06139566d85ad6a50c30af6d3f09d19a3eca418d 100644 (file)
@@ -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)
index f5bd636d81f98c1b481b0919776ed2051d5fddaf..9e90c77764d020715c4b6bc94ad71deeee6f19aa 100644 (file)
@@ -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);
index 7e1bfd1e560dc0b12f7286048aee1bd8c0b837d7..07c400f5d3bf31337449629435cfe5f1dc5949c7 100644 (file)
@@ -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)));
 
index e2a44d2c8b71e29d28a02138543ea4faf0f3f44a..51093d51b512abb12fc687c7b391ee0fea9b28db 100644 (file)
@@ -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)
        {
index 3f6b9b6d22d676abd06947c077560d28e6924307..299c88535446724e3819fc5f90c67ac07efe0693 100644 (file)
@@ -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;
index 8ade6794e6b0a958ff69113a2e429de520233ebb..c5777051871e81e8e8c6fce4f8fc7fff04835ab6 100644 (file)
@@ -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