]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Show a welcome window with banner, IP and MOTD on server connection (WIP: need a...
authorterencehill <piuntn@gmail.com>
Thu, 17 Nov 2016 12:46:59 +0000 (13:46 +0100)
committerterencehill <piuntn@gmail.com>
Thu, 17 Nov 2016 12:46:59 +0000 (13:46 +0100)
22 files changed:
commands.cfg
gfx/menu/luma/no_banner.tga [new file with mode: 0644]
gfx/menu/luma/skinvalues.txt
gfx/menu/luminos/skinvalues.txt
gfx/menu/wickedx/skinvalues.txt
gfx/menu/xaw/skinvalues.txt
qcsrc/client/main.qc
qcsrc/common/net_linked.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/skin-customizables.inc
qcsrc/menu/xonotic/_mod.inc
qcsrc/menu/xonotic/_mod.qh
qcsrc/menu/xonotic/dialog_welcome.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_welcome.qh [new file with mode: 0644]
qcsrc/menu/xonotic/mainwindow.qc
qcsrc/menu/xonotic/textbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/textbox.qh [new file with mode: 0644]
qcsrc/server/client.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/cmd.qh

index a8de9b95cb842512272a49bed77a2c1e4b026d6a..8b8c14ba7ead518c56dc948f2afc90b6e4327c54 100644 (file)
@@ -147,6 +147,7 @@ seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they ar
 // commented out commands are really only intended for internal use, or already have declaration in the engine
 alias autoswitch           "qc_cmd_cmd    autoswitch           ${* ?}" // Whether or not to switch automatically when getting a better weapon
 alias clientversion        "qc_cmd_cmd    clientversion        ${* ?}" // Release version of the game
+//alias getserverpic       "qc_cmd_cmd    getserverpic         ${* ?}" // Retrieve server banner from the server
 //alias mv_getpicture      "qc_cmd_cmd    mv_getpicture        ${* ?}" // Retrieve mapshot picture from the server
 alias join                 "qc_cmd_cmd    join                 ${* ?}" // Become a player in the game
 alias ready                "qc_cmd_cmd    ready                ${* ?}" // Qualify as ready to end warmup stage (or restart server if allowed)
diff --git a/gfx/menu/luma/no_banner.tga b/gfx/menu/luma/no_banner.tga
new file mode 100644 (file)
index 0000000..be731d0
Binary files /dev/null and b/gfx/menu/luma/no_banner.tga differ
index c997fea25772cd797dc361c60304db04e7cc3b5b..7531c7eea17c584ca06dab89b6056edfba54fb07 100644 (file)
@@ -92,9 +92,10 @@ COLOR_DIALOG_VIEW             '1 1 1'
 COLOR_DIALOG_MODEL            '1 1 1'
 COLOR_DIALOG_CROSSHAIR        '1 1 1'
 COLOR_DIALOG_HUD              '1 1 1'
-COLOR_DIALOG_SCREENSHOTVIEWER '1 1 1'
 COLOR_DIALOG_SERVERINFO       '1 1 1'
+COLOR_DIALOG_SCREENSHOTVIEWER '1 1 1'
 COLOR_DIALOG_FIRSTRUN         '1 1 1'
+COLOR_DIALOG_WELCOME          '1 1 1'
 COLOR_DIALOG_CVARS            '1 0.2 0.15'
 COLOR_DIALOG_HUDCONFIRM       '1 0.2 0.15'
 
index ca0384fb554135f88ed4bf13a41c3b3e849497f9..6eadef16a3c46db305139e5459db6fec13f5a83c 100755 (executable)
@@ -193,6 +193,8 @@ COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
 COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
+COLOR_DIALOG_FIRSTRUN           '1 1 1'
+COLOR_DIALOG_WELCOME            '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
index b7011a0b0e18369246a573e86f52dd0d22174bb4..d4fbad9f815146dcf1281a98c851eaebd86ae8c4 100644 (file)
@@ -193,6 +193,8 @@ COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
 COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
+COLOR_DIALOG_FIRSTRUN           '1 1 1'
+COLOR_DIALOG_WELCOME            '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
index 5f4bbaad40211135e157b03f89e82e99ef337475..01f3c9e54794ba914a508c664f282a31436d50cb 100644 (file)
@@ -37,6 +37,8 @@ COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
 COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
+COLOR_DIALOG_FIRSTRUN           '1 1 1'
+COLOR_DIALOG_WELCOME            '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
index 36ca217240f0ba0e8a6966fcb25b06829df43491..024029019ec66d569d98367a3181a35257c68344 100644 (file)
@@ -1226,6 +1226,42 @@ NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
        }
 }
 
+string welcomedialog_args;
+NET_HANDLE(TE_CSQC_SERVERINFO, bool isNew)
+{
+       if(welcomedialog_args)
+               strunzone(welcomedialog_args);
+       welcomedialog_args = strcat("name \"", ReadString(), "\"");
+       welcomedialog_args = strcat(welcomedialog_args, " ip \"", ReadString(), "\"");
+       welcomedialog_args = strcat(welcomedialog_args, " motd \"", MakeConsoleSafe(strreplace("\n", "\\n", ReadString())), "\"");
+       string pic = ReadString();
+       if(pic == "" || PreviewExists(pic) )
+       {
+               if(pic != "")
+                       welcomedialog_args = strcat(welcomedialog_args, " pic \"", pic, "\"");
+               localcmd("\nmenu_cmd directmenu Welcome ", welcomedialog_args, "\n");
+               welcomedialog_args = string_null;
+       } else {
+               welcomedialog_args = strzone(welcomedialog_args);
+               print(_("Requesting server banner...\n"));
+               localcmd("\ncmd getserverpic\n");
+       }
+       return true;
+}
+
+NET_HANDLE(TE_CSQC_SERVERINFO_PIC, bool isNew)
+{
+       if(welcomedialog_args)
+       {
+               localcmd("\nmenu_cmd directmenu Welcome ", strcat(welcomedialog_args, " pic \"", ReadPicture(), "\""), "\n");
+               strunzone(welcomedialog_args);
+               welcomedialog_args = string_null;
+       }
+       else // just get the image, we don't want to display the welcome dialog
+               ReadPicture();
+       return true;
+}
+
 string _getcommandkey(string cmd_name, string command, bool forcename)
 {
        string keys;
index 9cd2094a68852b59b4775090bdf40ea124701543..1fcb3d12a75430530cec93df66a34c5ee54fa901 100644 (file)
@@ -5,6 +5,8 @@ REGISTER_NET_TEMP(TE_CSQC_RACE)
 REGISTER_NET_TEMP(TE_CSQC_TEAMNAGGER)
 REGISTER_NET_TEMP(TE_CSQC_PINGPLREPORT)
 REGISTER_NET_TEMP(TE_CSQC_WEAPONCOMPLAIN)
+REGISTER_NET_TEMP(TE_CSQC_SERVERINFO)
+REGISTER_NET_TEMP(TE_CSQC_SERVERINFO_PIC)
 REGISTER_NET_TEMP(TE_CSQC_VEHICLESETUP)
 
 const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
index 87636d24e8446fddd1566e1b6c2e5edf9601e428..7c7cadecffd8378d77608c504cbfbbd2f29d24e9 100644 (file)
@@ -37,6 +37,16 @@ vector real_origin(entity ent)
        return v;
 }
 #endif
+bool ImageExists(string img)
+{
+       if(fexists(strcat(img, ".tga"))) return true;
+       if(fexists(strcat(img, ".png"))) return true;
+       if(fexists(strcat(img, ".jpg"))) return true;
+       if(fexists(strcat(img, ".pcx"))) return true;
+
+       return false;
+}
 
 string wordwrap_buffer;
 
index 57f9a2217c42d5a502e8268c139bd8f082094d29..8b1bd064e20f5499e4794f4895b8906a2ea7c1de 100644 (file)
@@ -32,6 +32,7 @@ string ftos_decimals(float number, float decimals);
 string ftos_mindecimals(float number);
 
 bool fexists(string f);
+bool ImageExists(string img);
 
 // unzone the string, and return it as tempstring. Safe to be called on string_null
 string fstrunzone(string s);
index 72aadf6247bac401778744fe630ea81443979fba..571dfdb0520472f925c6af529f0f86f6f7106462 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <common/command/_mod.qh>
 
+.void(entity me, float argsbuf) readInputArgs;
 .entity firstChild, nextSibling;
 
 string _dumptree_space;
@@ -94,6 +95,27 @@ void GameCommand(string theCommand)
                        m_play_click_sound(MENU_SOUND_OPEN);
                        m_goto(strcat(filter, argv(1))); // switch to a menu item
                }
+               else if(argc > 2 && !isdemo())
+               {
+                       entity e = NULL;
+                       float argsbuf = 0;
+                       string s = strzone(argv(1)); // dialog name
+                       for(int i = 0; (e = nextent(e)); )
+                               if(e.classname != "vtbl" && e.name == strcat(filter, s))
+                               {
+                                       argsbuf = buf_create();
+                                       if(argsbuf >= 0)
+                                       if(e.readInputArgs)
+                                       {
+                                               for(i = 2; i < argc; ++i)
+                                                       bufstr_add(argsbuf, argv(i), 1);
+                                               e.readInputArgs(e, argsbuf);
+                                               m_goto(strcat(filter, s));
+                                       }
+                                       if(argsbuf >= 0)
+                                               buf_del(argsbuf);
+                               }
+               }
                return;
        }
 
index d5e1f82eba4ab0ece3d7fb7995ec4b7838c455a3..d73d7e7db745efd82756af5cb5d678534a03a7a3 100644 (file)
@@ -70,6 +70,7 @@ SKINBEGIN
        SKINVECTOR(COLOR_DIALOG_CROSSHAIR, '1 0.7 0.7');
        SKINVECTOR(COLOR_DIALOG_HUD, '1 0.7 0.7');
        SKINVECTOR(COLOR_DIALOG_SERVERINFO, '0.7 0.7 1');
+       SKINVECTOR(COLOR_DIALOG_WELCOME, '1 0.7 0.7');
        SKINVECTOR(COLOR_DIALOG_CVARS, '1 0 0');
        SKINVECTOR(COLOR_DIALOG_SCREENSHOTVIEWER, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_HUDCONFIRM, '1 0 0');
index 577c8225803461225c818ce07f6cf396d1806f10..18e77ba389fd6bebfba51e487db6b52ce22079c6 100644 (file)
@@ -80,6 +80,7 @@
 #include <menu/xonotic/dialog_singleplayer_winner.qc>
 #include <menu/xonotic/dialog_teamselect.qc>
 #include <menu/xonotic/dialog_uid2name.qc>
+#include <menu/xonotic/dialog_welcome.qc>
 #include <menu/xonotic/gametypelist.qc>
 #include <menu/xonotic/hudskinlist.qc>
 #include <menu/xonotic/image.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 b6e34eff247606d774eb1d321fe9f7539071d3ff..741d868009fe2332b629481e557be4859a98a559 100644 (file)
@@ -80,6 +80,7 @@
 #include <menu/xonotic/dialog_singleplayer_winner.qh>
 #include <menu/xonotic/dialog_teamselect.qh>
 #include <menu/xonotic/dialog_uid2name.qh>
+#include <menu/xonotic/dialog_welcome.qh>
 #include <menu/xonotic/gametypelist.qh>
 #include <menu/xonotic/hudskinlist.qh>
 #include <menu/xonotic/image.qh>
diff --git a/qcsrc/menu/xonotic/dialog_welcome.qc b/qcsrc/menu/xonotic/dialog_welcome.qc
new file mode 100644 (file)
index 0000000..6ef42a5
--- /dev/null
@@ -0,0 +1,101 @@
+#include "dialog_welcome.qh"
+
+#include "image.qh"
+#include "textlabel.qh"
+#include "textbox.qh"
+#include "radiobutton.qh"
+#include "commandbutton.qh"
+#include "slider.qh"
+
+void welcomeDialog_resetStrings(entity me)
+{
+       if(me.serverinfo_name)
+               strunzone(me.serverinfo_name);
+       me.serverinfo_name = strzone(_("<NO NAME>"));
+
+       if(me.serverinfo_ip)
+               strunzone(me.serverinfo_ip);
+       me.serverinfo_ip = strzone(_("<NO IP>"));
+
+       if(me.serverinfo_MOTD)
+               strunzone(me.serverinfo_MOTD);
+       me.serverinfo_MOTD = strzone(_("<NO MOTD>"));
+
+       if(me.serverinfo_pic)
+               strunzone(me.serverinfo_pic);
+       me.serverinfo_pic = strzone("no_banner");
+}
+void XonoticWelcomeDialog_configureDialog(entity me)
+{
+       welcomeDialog_resetStrings(me);
+       SUPER(XonoticWelcomeDialog).configureDialog(me);
+}
+void XonoticWelcomeDialog_readInputArgs(entity me, float argsbuf)
+{
+       int i = 0;
+       string s;
+       welcomeDialog_resetStrings(me);
+       if(argsbuf >= 0)
+       while((s = bufstr_get(argsbuf, i)) != "")
+       {
+               if(s == "name")
+               {
+                       if(me.serverinfo_name)
+                               strunzone(me.serverinfo_name);
+                       me.serverinfo_name = strzone(bufstr_get(argsbuf, i + 1));
+                       ++i;
+               }
+               else if(s == "ip")
+               {
+                       if(me.serverinfo_ip)
+                               strunzone(me.serverinfo_ip);
+                       me.serverinfo_ip = strzone(bufstr_get(argsbuf, i + 1));
+                       ++i;
+               }
+               else if(s == "motd")
+               {
+                       if(me.serverinfo_MOTD)
+                               strunzone(me.serverinfo_MOTD);
+                       me.serverinfo_MOTD = strzone(bufstr_get(argsbuf, i + 1));
+                       ++i;
+               }
+               else if(s == "pic")
+               {
+                       if(me.serverinfo_pic)
+                               strunzone(me.serverinfo_pic);
+                       me.serverinfo_pic = strzone(strcat("/", bufstr_get(argsbuf, i + 1)));
+                       ++i;
+               }
+               ++i;
+       }
+       me.serverinfo_name_ent.setText(me.serverinfo_name_ent, me.serverinfo_name);
+       me.serverinfo_ip_ent.setText(me.serverinfo_ip_ent, me.serverinfo_ip);
+       me.serverinfo_MOTD_ent.setText(me.serverinfo_MOTD_ent, me.serverinfo_MOTD);
+
+       if(me.serverinfo_pic_ent.src)
+               strunzone(me.serverinfo_pic_ent.src);
+       me.serverinfo_pic_ent.src = strzone(me.serverinfo_pic);
+}
+
+void XonoticWelcomeDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 4, me.columns / 2, me.serverinfo_pic_ent = makeXonoticImage(string_null, 4.0/3.0));
+
+       me.gotoRC(me, 1, me.columns / 2);
+               me.TD(me, 1, me.columns / 2, me.serverinfo_name_ent = makeXonoticTextLabel(0, ""));
+       me.gotoRC(me, 2, me.columns / 2);
+               me.TD(me, 1, me.columns / 2, me.serverinfo_ip_ent = makeXonoticTextLabel(0, ""));
+
+       me.gotoRC(me, 4, 0);
+               me.TD(me, me.rows - 4 - 1, me.columns, me.serverinfo_MOTD_ent = makeXonoticTextBox());
+                       me.serverinfo_MOTD_ent.allowColors = 1;
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns / 2, e = makeXonoticCommandButton(_("Disconnect"), '0 0 0', "disconnect", COMMANDBUTTON_CLOSE));
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+                       e.preferredFocusPriority = 1;
+}
diff --git a/qcsrc/menu/xonotic/dialog_welcome.qh b/qcsrc/menu/xonotic/dialog_welcome.qh
new file mode 100644 (file)
index 0000000..e3b569f
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "rootdialog.qh"
+CLASS(XonoticWelcomeDialog, XonoticRootDialog)
+       METHOD(XonoticWelcomeDialog, fill, void(entity));
+       ATTRIB(XonoticWelcomeDialog, title, string, _("Welcome"));
+       ATTRIB(XonoticWelcomeDialog, color, vector, SKINCOLOR_DIALOG_WELCOME);
+       ATTRIB(XonoticWelcomeDialog, intendedWidth, float, 0.7);
+       ATTRIB(XonoticWelcomeDialog, rows, float, 14);
+       ATTRIB(XonoticWelcomeDialog, columns, float, 4);
+       ATTRIB(XonoticWelcomeDialog, name, string, "Welcome");
+
+       METHOD(XonoticWelcomeDialog, configureDialog, void(entity));
+       METHOD(XonoticWelcomeDialog, readInputArgs, void(entity, float));
+       ATTRIB(XonoticWelcomeDialog, serverinfo_name, string, string_null);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_name_ent, entity, world);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_ip, string, string_null);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_ip_ent, entity, world);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_MOTD, string, string_null);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_MOTD_ent, entity, world);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_pic, string, string_null);
+       ATTRIB(XonoticWelcomeDialog, serverinfo_pic_ent, entity, NULL);
+ENDCLASS(XonoticWelcomeDialog)
index 0e071c2e71efc20321722e13b4246f46ec81cfda..895b6996cb599e4c2392fe467a0ee60c0dca3e93 100644 (file)
@@ -38,6 +38,7 @@
 #include "dialog_multiplayer_create_mutators.qh"
 #include "dialog_sandboxtools.qh"
 #include "dialog_monstertools.qh"
+#include "dialog_welcome.qh"
 #include "dialog_teamselect.qh"
 #include "dialog_uid2name.qh"
 #include "dialog_singleplayer.qh"
@@ -233,6 +234,10 @@ void MainWindow_configureMainWindow(entity me)
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
 
+       i = NEW(XonoticWelcomeDialog);
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
 
        // main dialogs/windows
        me.mainNexposee = n = NEW(XonoticNexposee);
diff --git a/qcsrc/menu/xonotic/textbox.qc b/qcsrc/menu/xonotic/textbox.qc
new file mode 100644 (file)
index 0000000..bc86f5f
--- /dev/null
@@ -0,0 +1,67 @@
+#include "textbox.qh"
+
+entity makeXonoticTextBox()
+{
+       entity me;
+       me = NEW(XonoticTextBox);
+       me.configureXonoticTextBox(me);
+       return me;
+}
+void XonoticTextBox_configureXonoticTextBox(entity me)
+{
+       me.configureListBox(me, me.scrollbarWidth, 1); // item height gets set up later
+}
+void XonoticTextBox_setSelected(entity me, float i)
+{
+       // nothing
+}
+void XonoticTextBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemHeight = me.rowsPerItem * me.fontSize / absSize_y;
+       SUPER(XonoticTextBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+       me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
+       me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
+       me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+}
+void XonoticTextBox_setText(entity me, string theText)
+{
+       int i, k;
+       string ts;
+       if(me.textbuf >= 0)
+               buf_del(me.textbuf);
+       me.textbuf = buf_create();
+       string s = strzone(theText);
+       me.nItems = 0;
+       k = tokenizebyseparator(s, "\\n");
+       for(i = 0; i < k; ++i)
+       {
+               getWrappedLine_remaining = argv(i);
+               if(!getWrappedLine_remaining)
+               {
+                       bufstr_add(me.textbuf, "", 1);
+                       ++me.nItems;
+               }
+               else while(getWrappedLine_remaining)
+               {
+                       ts = getWrappedLine(1 - me.controlWidth, me.realFontSize, draw_TextWidth_WithColors);
+                       if (ts != "")
+                       {
+                               bufstr_add(me.textbuf, ts, 1);
+                               ++me.nItems;
+                       }
+               }
+       }
+       strunzone(s);
+       me.textbufSize = buf_getsize(me.textbuf);
+}
+void XonoticTextBox_destroy(entity me)
+{
+       if(me.textbuf >= 0)
+               buf_del(me.textbuf);
+}
+void XonoticTextBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
+{
+       if(me.textbufSize > 0)
+               draw_CenterText(me.realUpperMargin * eY + 0.5 * eX, bufstr_get(me.textbuf, i), me.realFontSize, '1 1 1', 1, me.allowColors);
+}
diff --git a/qcsrc/menu/xonotic/textbox.qh b/qcsrc/menu/xonotic/textbox.qh
new file mode 100644 (file)
index 0000000..536621b
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "../item/listbox.qh"
+CLASS(XonoticTextBox, ListBox)
+       METHOD(XonoticTextBox, configureXonoticTextBox, void(entity));
+       ATTRIB(XonoticTextBox, fontSize, float, SKINFONTSIZE_NORMAL);
+       ATTRIB(XonoticTextBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR);
+       ATTRIB(XonoticTextBox, src, string, SKINGFX_SCROLLBAR);
+       ATTRIB(XonoticTextBox, tolerance, vector, SKINTOLERANCE_SLIDER);
+       ATTRIB(XonoticTextBox, rowsPerItem, float, 1);
+       METHOD(XonoticTextBox, resizeNotify, void(entity, vector, vector, vector, vector));
+       ATTRIB(XonoticTextBox, color, vector, SKINCOLOR_SCROLLBAR_N);
+       ATTRIB(XonoticTextBox, colorF, vector, SKINCOLOR_SCROLLBAR_F);
+       ATTRIB(XonoticTextBox, color2, vector, SKINCOLOR_SCROLLBAR_S);
+       ATTRIB(XonoticTextBox, colorC, vector, SKINCOLOR_SCROLLBAR_C);
+       ATTRIB(XonoticTextBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND);
+       ATTRIB(XonoticTextBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND);
+
+       ATTRIB(XonoticTextBox, realFontSize, vector, '0 0 0');
+       ATTRIB(XonoticTextBox, realUpperMargin, float, 0);
+
+       METHOD(XonoticTextBox, setSelected, void(entity, float));
+       METHOD(XonoticTextBox, destroy, void(entity));
+       ATTRIB(XonoticTextBox, textbuf, int, -1);
+       ATTRIB(XonoticTextBox, textbufSize, int, 0);
+       ATTRIB(XonoticTextBox, allowColors, bool, 0);
+       METHOD(XonoticTextBox, setText, void(entity, string));
+       METHOD(XonoticTextBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
+ENDCLASS(XonoticTextBox)
+entity makeXonoticTextBox();
index da66ece3bb813fa6776d5c9ad183311ba63218af..814cb327832138a2f9d6267611b91c68f3c88646 100644 (file)
@@ -812,6 +812,35 @@ void DecodeLevelParms(entity this)
 
        MUTATOR_CALLHOOK(DecodeLevelParms);
 }
+void serverinfo_welcomemessage_send(entity this)
+{
+       msg_entity = this;
+       WriteHeader(MSG_ONE, TE_CSQC_SERVERINFO);
+       WriteString(MSG_ONE, "128.03.192.999"); // FIXME: send the real server ip
+       WriteString(MSG_ONE, autocvar_hostname);
+       WriteString(MSG_ONE, getwelcomemessage(this));
+       string pic = strcat("128.03.192.999", "/banner");
+       if(!ImageExists(pic))
+       {
+               print("Warning: image %s doesn't exist!\n", pic);
+               pic = "";
+       }
+       WriteString(MSG_ONE, pic);
+}
+
+void serverinfo_pic_send(entity this)
+{
+       string pic = strcat("128.03.192.999", "/banner");
+       if(!ImageExists(pic))
+       {
+               print("Cannot send %s, file doesn't exist!\n", pic);
+               return;
+       }
+       msg_entity = this;
+       WriteHeader(MSG_ONE, TE_CSQC_SERVERINFO_PIC);
+       WritePicture(MSG_ONE, pic, 3072);
+}
 
 /*
 =============
@@ -1212,7 +1241,10 @@ void ClientConnect(entity this)
        this.model_randomizer = random();
 
        if (IS_REAL_CLIENT(this))
+       {
+               serverinfo_welcomemessage_send(this);
                sv_notice_join(this);
+       }
 
        // update physics stats (players can spawn before physics runs)
        Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
index ea9610b16073048fc10fd73ac97a09e1147c8065..516ba360d1a639c731d527177ec8249faeff5603 100644 (file)
@@ -133,6 +133,26 @@ void ClientCommand_clientversion(entity caller, float request, float argc)  // i
                }
        }
 }
+void ClientCommand_getserverpic(entity caller, float request) // internal command, used only by code
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       serverinfo_pic_send(caller);
+                       return;
+               }
+
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(caller, "\nUsage:^3 cmd getserverpic\n");
+                       sprint(caller, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
 
 void ClientCommand_mv_getpicture(entity caller, float request, float argc)  // internal command, used only by code
 {
@@ -635,6 +655,7 @@ void ClientCommand_(entity caller, float request)
        CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(ent, request, arguments), "Whether or not to switch automatically when getting a better weapon") \
        CLIENT_COMMAND("clientversion", ClientCommand_clientversion(ent, request, arguments), "Release version of the game") \
        CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(ent, request, arguments), "Retrieve mapshot picture from the server") \
+       CLIENT_COMMAND("getserverpic", ClientCommand_getserverpic(ent, request), "Retrieve server banner from the server") \
        CLIENT_COMMAND("join", ClientCommand_join(ent, request), "Become a player in the game") \
        CLIENT_COMMAND("physics", ClientCommand_physics(ent, request, arguments), "Change physics set") \
        CLIENT_COMMAND("ready", ClientCommand_ready(ent, request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
@@ -721,6 +742,7 @@ void SV_ParseClientCommand(entity this, string command)
                // exempt commands which are not subject to floodcheck
                case "begin": break;                               // handled by engine in host_cmd.c
                case "download": break;                            // handled by engine in cl_parse.c
+               case "getserverpic": break; // handled by server in this file
                case "mv_getpicture": break;                       // handled by server in this file
                case "pause": break;                               // handled by engine in host_cmd.c
                case "prespawn": break;                            // handled by engine in host_cmd.c
index 5f2c86e4086c89d6f8bf4547f7b6659aef421785..337bde01ce1f82937ef2df96ee82037b2ab9ea68 100644 (file)
@@ -6,5 +6,8 @@
 
 string MapVote_Suggest(entity this, string m);
 
+void serverinfo_welcomemessage_send(entity this);
+void serverinfo_pic_send(entity this);
+
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
 void ClientCommand_macro_write_aliases(float fh);