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;
614 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
618 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);
619 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
620 category_drawn = TRUE;
624 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
626 s = gethostcachestring(SLIST_FIELD_QCSTATUS, cache);
627 m = tokenizebyseparator(s, ":");
632 versionstr = argv(1);
638 for(j = 2; j < m; ++j)
642 k = substring(argv(j), 0, 1);
643 v = substring(argv(j), 1, -1);
654 #ifdef COMPAT_NO_MOD_IS_XONOTIC
660 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
661 s = gethostcachestring(SLIST_FIELD_MOD, cache);
663 if(modname == "Xonotic")
667 // list the mods here on which the pure server check actually works
668 if(modname != "Xonotic")
669 if(modname != "MinstaGib")
672 if(modname != "NewToys")
675 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, cache) <= 0)
676 theAlpha = SKINALPHA_SERVERLIST_FULL;
677 else if(freeslots == 0)
678 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
679 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache))
680 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
684 p = gethostcachenumber(SLIST_FIELD_PING, cache);
687 #define PING_HIGH 500
689 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
690 else if(p < PING_MED)
691 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
692 else if(p < PING_HIGH)
694 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
695 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
700 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
703 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, cache))
705 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
706 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
709 s = gethostcachestring(SLIST_FIELD_CNAME, cache);
712 if(substring(s, 0, 1) == "[")
717 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
723 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
724 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
726 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
727 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
732 if(cvar("crypto_aeslevel") >= 2)
737 if(cvar("crypto_aeslevel") >= 1)
747 // 2: AES recommended but not available
748 // 3: AES possible and will be used
749 // 4: AES recommended and will be used
753 vector iconSize = '0 0 0';
754 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
755 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
757 vector iconPos = '0 0 0';
758 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
759 iconPos_y = (1 - iconSize_y) * 0.5;
763 if not(me.seenIPv4 && me.seenIPv6)
765 iconPos_x += iconSize_x * 0.5;
767 else if(me.seenIPv4 && me.seenIPv6)
771 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
773 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
775 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
776 iconPos_x += iconSize_x;
781 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
782 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
784 iconPos_x += iconSize_x;
786 if(modname == "Xonotic")
790 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
791 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
796 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
797 if(draw_PictureSize(n) == '0 0 0')
798 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
800 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
802 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
804 iconPos_x += iconSize_x;
806 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
808 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
809 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
811 iconPos_x += iconSize_x;
815 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
816 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, cache), me.columnNameSize, 0, me.realFontSize);
817 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
818 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, cache), me.columnMapSize, 0, me.realFontSize);
819 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
820 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
821 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
822 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, cache)));
823 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
826 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
831 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
832 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
834 if(scan == K_ENTER || scan == K_KP_ENTER)
836 ServerList_Connect_Click(NULL, me);
839 else if(scan == K_MOUSE2 || scan == K_SPACE)
843 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
844 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
849 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
854 ToggleFavorite(me.selectedServer);
855 me.ipAddressBoxFocused = -1;
860 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
862 else if(!me.controlledTextbox)
865 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);