2 CLASS(XonoticServerList) EXTENDS(XonoticListBox)
3 METHOD(XonoticServerList, configureXonoticServerList, void(entity))
4 ATTRIB(XonoticServerList, rowsPerItem, float, 1)
5 METHOD(XonoticServerList, draw, void(entity))
6 METHOD(XonoticServerList, drawListBoxItem, void(entity, float, vector, float))
7 METHOD(XonoticServerList, clickListBoxItem, void(entity, float, vector))
8 METHOD(XonoticServerList, resizeNotify, void(entity, vector, vector, vector, vector))
9 METHOD(XonoticServerList, keyDown, float(entity, float, float, float))
11 ATTRIB(XonoticServerList, iconsSizeFactor, float, 0.85)
13 ATTRIB(XonoticServerList, realFontSize, vector, '0 0 0')
14 ATTRIB(XonoticServerList, realUpperMargin, float, 0)
15 ATTRIB(XonoticServerList, columnIconsOrigin, float, 0)
16 ATTRIB(XonoticServerList, columnIconsSize, float, 0)
17 ATTRIB(XonoticServerList, columnPingOrigin, float, 0)
18 ATTRIB(XonoticServerList, columnPingSize, float, 0)
19 ATTRIB(XonoticServerList, columnNameOrigin, float, 0)
20 ATTRIB(XonoticServerList, columnNameSize, float, 0)
21 ATTRIB(XonoticServerList, columnMapOrigin, float, 0)
22 ATTRIB(XonoticServerList, columnMapSize, float, 0)
23 ATTRIB(XonoticServerList, columnTypeOrigin, float, 0)
24 ATTRIB(XonoticServerList, columnTypeSize, float, 0)
25 ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0)
26 ATTRIB(XonoticServerList, columnPlayersSize, float, 0)
28 ATTRIB(XonoticServerList, selectedServer, string, string_null) // to restore selected server when needed
29 METHOD(XonoticServerList, setSelected, void(entity, float))
30 METHOD(XonoticServerList, setSortOrder, void(entity, float, float))
31 ATTRIB(XonoticServerList, filterShowEmpty, float, 1)
32 ATTRIB(XonoticServerList, filterShowFull, float, 1)
33 ATTRIB(XonoticServerList, filterString, string, string_null)
34 ATTRIB(XonoticServerList, controlledTextbox, entity, NULL)
35 ATTRIB(XonoticServerList, ipAddressBox, entity, NULL)
36 ATTRIB(XonoticServerList, favoriteButton, entity, NULL)
37 ATTRIB(XonoticServerList, nextRefreshTime, float, 0)
38 METHOD(XonoticServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
39 ATTRIB(XonoticServerList, needsRefresh, float, 1)
40 METHOD(XonoticServerList, focusEnter, void(entity))
41 METHOD(XonoticServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
42 ATTRIB(XonoticServerList, sortButton1, entity, NULL)
43 ATTRIB(XonoticServerList, sortButton2, entity, NULL)
44 ATTRIB(XonoticServerList, sortButton3, entity, NULL)
45 ATTRIB(XonoticServerList, sortButton4, entity, NULL)
46 ATTRIB(XonoticServerList, sortButton5, entity, NULL)
47 ATTRIB(XonoticServerList, connectButton, entity, NULL)
48 ATTRIB(XonoticServerList, infoButton, entity, NULL)
49 ATTRIB(XonoticServerList, currentSortOrder, float, 0)
50 ATTRIB(XonoticServerList, currentSortField, float, -1)
51 ATTRIB(XonoticServerList, lastClickedServer, float, -1)
52 ATTRIB(XonoticServerList, lastClickedTime, float, 0)
54 ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1)
56 ATTRIB(XonoticServerList, seenIPv4, float, 0)
57 ATTRIB(XonoticServerList, seenIPv6, float, 0)
58 ENDCLASS(XonoticServerList)
59 entity makeXonoticServerList();
60 void ServerList_Connect_Click(entity btn, entity me);
61 void ServerList_ShowEmpty_Click(entity box, entity me);
62 void ServerList_ShowFull_Click(entity box, entity me);
63 void ServerList_Filter_Change(entity box, entity me);
64 void ServerList_Favorite_Click(entity btn, entity me);
65 void ServerList_Info_Click(entity btn, entity me);
66 void ServerList_Update_favoriteButton(entity btn, entity me);
68 float SLIST_FIELD_CNAME;
69 float SLIST_FIELD_PING;
70 float SLIST_FIELD_GAME;
71 float SLIST_FIELD_MOD;
72 float SLIST_FIELD_MAP;
73 float SLIST_FIELD_NAME;
74 float SLIST_FIELD_MAXPLAYERS;
75 float SLIST_FIELD_NUMPLAYERS;
76 float SLIST_FIELD_NUMHUMANS;
77 float SLIST_FIELD_NUMBOTS;
78 float SLIST_FIELD_PROTOCOL;
79 float SLIST_FIELD_FREESLOTS;
80 float SLIST_FIELD_PLAYERS;
81 float SLIST_FIELD_QCSTATUS;
82 float SLIST_FIELD_ISFAVORITE;
86 void ServerList_UpdateFieldIDs()
88 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
89 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
90 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
91 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
92 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
93 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
94 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
95 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
96 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
97 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
98 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
99 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
100 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
101 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
102 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
105 float IsFavorite(string srv)
111 srv = netaddress_resolve(srv, 26000);
114 p = crypto_getidfp(srv);
115 n = tokenize_console(cvar_string("net_slist_favorites"));
116 for(i = 0; i < n; ++i)
118 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
126 if(srv == netaddress_resolve(argv(i), 26000))
133 void ToggleFavorite(string srv)
135 string s, s0, s1, s2, srv_resolved, p;
137 srv_resolved = netaddress_resolve(srv, 26000);
138 p = crypto_getidfp(srv_resolved);
139 s = cvar_string("net_slist_favorites");
140 n = tokenize_console(s);
142 for(i = 0; i < n; ++i)
144 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
152 if(srv_resolved != netaddress_resolve(argv(i), 26000))
157 s0 = substring(s, 0, argv_end_index(i - 1));
159 s2 = substring(s, argv_start_index(i + 1), -1);
160 if(s0 != "" && s2 != "")
162 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
163 s = cvar_string("net_slist_favorites");
164 n = tokenize_console(s);
175 cvar_set("net_slist_favorites", strcat(s, s1, p));
177 cvar_set("net_slist_favorites", strcat(s, s1, srv));
183 void ServerList_Update_favoriteButton(entity btn, entity me)
185 if(IsFavorite(me.ipAddressBox.text))
186 me.favoriteButton.setText(me.favoriteButton, _("Remove"));
188 me.favoriteButton.setText(me.favoriteButton, _("Bookmark"));
191 entity makeXonoticServerList()
194 me = spawnXonoticServerList();
195 me.configureXonoticServerList(me);
198 void XonoticServerList_configureXonoticServerList(entity me)
200 me.configureXonoticListBox(me);
202 ServerList_UpdateFieldIDs();
206 void XonoticServerList_setSelected(entity me, float i)
209 save = me.selectedItem;
210 SUPER(XonoticServerList).setSelected(me, i);
212 if(me.selectedItem == save)
217 //if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
218 // return; // sorry, it would be wrong
220 if(me.selectedServer)
221 strunzone(me.selectedServer);
222 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
224 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
225 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
226 me.ipAddressBoxFocused = -1;
228 void XonoticServerList_refreshServerList(entity me, float mode)
230 // 0: just reparametrize
231 // 1: also ask for new servers
233 //print("refresh of type ", ftos(mode), "\n");
234 /* if(mode == 2) // borken
237 localcmd("net_slist\n");
238 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
242 float m, o, i, n; // moin moin
243 string s, typestr, modstr;
246 m = strstrofs(s, ":", 0);
249 typestr = substring(s, 0, m);
250 s = substring(s, m + 1, strlen(s) - m - 1);
251 while(substring(s, 0, 1) == " ")
252 s = substring(s, 1, strlen(s) - 1);
257 modstr = cvar_string("menu_slist_modfilter");
259 m = SLIST_MASK_AND - 1;
260 resethostcachemasks();
262 // ping: reject negative ping (no idea why this happens in the first place, engine bug)
263 sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
266 if(!me.filterShowFull)
268 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
269 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
273 if(!me.filterShowEmpty)
274 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
276 // gametype filtering
278 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
283 if(substring(modstr, 0, 1) == "!")
284 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
286 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
290 n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
291 for(i = 0; i < n; ++i)
293 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
295 m = SLIST_MASK_OR - 1;
298 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
299 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
300 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
301 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
303 o = 2; // favorites first
304 if(me.currentSortOrder < 0)
305 o |= 1; // descending
306 sethostcachesort(me.currentSortField, o);
312 void XonoticServerList_focusEnter(entity me)
314 if(time < me.nextRefreshTime)
316 //print("sorry, no refresh yet\n");
319 me.nextRefreshTime = time + 10;
320 me.refreshServerList(me, 1);
322 float category_drawn;
323 void XonoticServerList_draw(entity me)
325 float i, found, owned;
327 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
331 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
334 if(me.currentSortField == -1)
336 me.setSortOrder(me, SLIST_FIELD_PING, +1);
337 me.refreshServerList(me, 2);
339 else if(me.needsRefresh == 1)
341 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
343 else if(me.needsRefresh == 2)
346 me.refreshServerList(me, 0);
349 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
351 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) + 1;
353 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
354 me.infoButton.disabled = ((me.nItems == 0) || !owned);
355 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
358 if(me.selectedServer)
360 for(i = 0; i < me.nItems; ++i)
361 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
363 if(i != me.selectedItem)
365 me.lastClickedServer = -1;
375 if(me.selectedItem >= me.nItems)
376 me.selectedItem = me.nItems - 1;
377 if(me.selectedServer)
378 strunzone(me.selectedServer);
379 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
384 if(me.selectedServer != me.ipAddressBox.text)
386 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
387 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
388 me.ipAddressBoxFocused = -1;
392 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
394 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
395 ServerList_Update_favoriteButton(NULL, me);
396 me.ipAddressBoxFocused = me.ipAddressBox.focused;
400 SUPER(XonoticServerList).draw(me);
402 void ServerList_PingSort_Click(entity btn, entity me)
404 me.setSortOrder(me, SLIST_FIELD_PING, +1);
406 void ServerList_NameSort_Click(entity btn, entity me)
408 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
410 void ServerList_MapSort_Click(entity btn, entity me)
412 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
414 void ServerList_PlayerSort_Click(entity btn, entity me)
416 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
418 void ServerList_TypeSort_Click(entity btn, entity me)
423 m = strstrofs(s, ":", 0);
426 s = substring(s, 0, m);
427 while(substring(s, m+1, 1) == " ") // skip spaces
433 for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
435 t = MapInfo_Type_ToString(i);
437 if(t == "") // it repeats (default case)
440 // choose the first one
441 s = MapInfo_Type_ToString(1);
446 // the type was found
447 // choose the next one
448 s = MapInfo_Type_ToString(i * 2);
450 s = MapInfo_Type_ToString(1);
457 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
459 me.controlledTextbox.setText(me.controlledTextbox, s);
460 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
461 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
462 //ServerList_Filter_Change(me.controlledTextbox, me);
464 void ServerList_Filter_Change(entity box, entity me)
467 strunzone(me.filterString);
469 me.filterString = strzone(box.text);
471 me.filterString = string_null;
472 me.refreshServerList(me, 0);
474 me.ipAddressBox.setText(me.ipAddressBox, "");
475 me.ipAddressBox.cursorPos = 0;
476 me.ipAddressBoxFocused = -1;
478 void ServerList_ShowEmpty_Click(entity box, entity me)
480 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
481 me.refreshServerList(me, 0);
483 me.ipAddressBox.setText(me.ipAddressBox, "");
484 me.ipAddressBox.cursorPos = 0;
485 me.ipAddressBoxFocused = -1;
487 void ServerList_ShowFull_Click(entity box, entity me)
489 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
490 me.refreshServerList(me, 0);
492 me.ipAddressBox.setText(me.ipAddressBox, "");
493 me.ipAddressBox.cursorPos = 0;
494 me.ipAddressBoxFocused = -1;
496 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
498 if(me.currentSortField == fld)
499 direction = -me.currentSortOrder;
500 me.currentSortOrder = direction;
501 me.currentSortField = fld;
502 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
503 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
504 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
505 me.sortButton4.forcePressed = 0;
506 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
508 if(me.selectedServer)
509 strunzone(me.selectedServer);
510 me.selectedServer = string_null;
511 me.refreshServerList(me, 0);
513 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
515 vector originInLBSpace, sizeInLBSpace;
516 originInLBSpace = eY * (-me.itemHeight);
517 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
519 vector originInDialogSpace, sizeInDialogSpace;
520 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
521 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
523 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
524 btn.Container_size_x = sizeInDialogSpace_x * theSize;
525 btn.setText(btn, theTitle);
526 btn.onClick = theFunc;
527 btn.onClickEntity = me;
530 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
532 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
534 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
535 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
536 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
538 me.columnIconsOrigin = 0;
539 me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
540 me.columnPingSize = me.realFontSize_x * 3;
541 me.columnMapSize = me.realFontSize_x * 10;
542 me.columnTypeSize = me.realFontSize_x * 4;
543 me.columnPlayersSize = me.realFontSize_x * 5;
544 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
545 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
546 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
547 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
548 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
549 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
551 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
552 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
553 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
554 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
555 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
558 f = me.currentSortField;
561 me.currentSortField = -1;
562 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
565 void ServerList_Connect_Click(entity btn, entity me)
567 if(me.ipAddressBox.text == "")
568 localcmd("connect ", me.selectedServer, "\n");
570 localcmd("connect ", me.ipAddressBox.text, "\n");
572 void ServerList_Favorite_Click(entity btn, entity me)
575 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
578 ToggleFavorite(me.ipAddressBox.text);
579 me.ipAddressBoxFocused = -1;
582 void ServerList_Info_Click(entity btn, entity me)
584 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
585 DialogOpenButton_Click(me, main.serverInfoDialog);
587 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
589 if(i == me.lastClickedServer)
590 if(time < me.lastClickedTime + 0.3)
593 ServerList_Connect_Click(NULL, me);
595 me.lastClickedServer = i;
596 me.lastClickedTime = time;
598 float category_drawn;
599 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
601 // layout: Ping, Server name, Map name, NP, TP, MP
606 float m, pure, freeslots, j, sflags;
607 string s, typestr, versionstr, k, v, modname;
609 print(sprintf("time: %f, category_drawn: %d, i: %d\n", time, category_drawn, i));
610 if(category_drawn) { i -= 1; }
613 draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth("category", 0, me.realFontSize)) * 0.5) * eX, "category", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
614 category_drawn = TRUE;
618 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
620 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
621 m = tokenizebyseparator(s, ":");
626 versionstr = argv(1);
632 for(j = 2; j < m; ++j)
636 k = substring(argv(j), 0, 1);
637 v = substring(argv(j), 1, -1);
648 #ifdef COMPAT_NO_MOD_IS_XONOTIC
654 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
655 s = gethostcachestring(SLIST_FIELD_MOD, i);
657 if(modname == "Xonotic")
661 // list the mods here on which the pure server check actually works
662 if(modname != "Xonotic")
663 if(modname != "MinstaGib")
666 if(modname != "NewToys")
669 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
670 theAlpha = SKINALPHA_SERVERLIST_FULL;
671 else if(freeslots == 0)
672 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
673 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
674 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
678 p = gethostcachenumber(SLIST_FIELD_PING, i);
681 #define PING_HIGH 500
683 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
684 else if(p < PING_MED)
685 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
686 else if(p < PING_HIGH)
688 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
689 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
694 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
697 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
699 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
700 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
703 s = gethostcachestring(SLIST_FIELD_CNAME, i);
706 if(substring(s, 0, 1) == "[")
711 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
717 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
718 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
720 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
721 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
726 if(cvar("crypto_aeslevel") >= 2)
731 if(cvar("crypto_aeslevel") >= 1)
741 // 2: AES recommended but not available
742 // 3: AES possible and will be used
743 // 4: AES recommended and will be used
747 vector iconSize = '0 0 0';
748 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
749 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
751 vector iconPos = '0 0 0';
752 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
753 iconPos_y = (1 - iconSize_y) * 0.5;
757 if not(me.seenIPv4 && me.seenIPv6)
759 iconPos_x += iconSize_x * 0.5;
761 else if(me.seenIPv4 && me.seenIPv6)
765 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
767 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
769 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
770 iconPos_x += iconSize_x;
775 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
776 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
778 iconPos_x += iconSize_x;
780 if(modname == "Xonotic")
784 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
785 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
790 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
791 if(draw_PictureSize(n) == '0 0 0')
792 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
794 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
796 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
798 iconPos_x += iconSize_x;
800 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
802 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
803 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
805 iconPos_x += iconSize_x;
809 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
810 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
811 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
812 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
813 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
814 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
815 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
816 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
817 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
820 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
825 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
826 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
828 if(scan == K_ENTER || scan == K_KP_ENTER)
830 ServerList_Connect_Click(NULL, me);
833 else if(scan == K_MOUSE2 || scan == K_SPACE)
837 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
838 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
843 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
848 ToggleFavorite(me.selectedServer);
849 me.ipAddressBoxFocused = -1;
854 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
856 else if(!me.controlledTextbox)
859 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);