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();
61 void ServerList_Connect_Click(entity btn, entity me);
62 void ServerList_ShowEmpty_Click(entity box, entity me);
63 void ServerList_ShowFull_Click(entity box, entity me);
64 void ServerList_Filter_Change(entity box, entity me);
65 void ServerList_Favorite_Click(entity btn, entity me);
66 void ServerList_Info_Click(entity btn, entity me);
67 void ServerList_Update_favoriteButton(entity btn, entity me);
69 #ifndef IMPLEMENTATION
70 float SLIST_FIELD_CNAME;
71 float SLIST_FIELD_PING;
72 float SLIST_FIELD_GAME;
73 float SLIST_FIELD_MOD;
74 float SLIST_FIELD_MAP;
75 float SLIST_FIELD_NAME;
76 float SLIST_FIELD_MAXPLAYERS;
77 float SLIST_FIELD_NUMPLAYERS;
78 float SLIST_FIELD_NUMHUMANS;
79 float SLIST_FIELD_NUMBOTS;
80 float SLIST_FIELD_PROTOCOL;
81 float SLIST_FIELD_FREESLOTS;
82 float SLIST_FIELD_PLAYERS;
83 float SLIST_FIELD_QCSTATUS;
84 float SLIST_FIELD_ISFAVORITE;
90 void ServerList_UpdateFieldIDs()
92 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
93 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
94 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
95 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
96 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
97 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
98 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
99 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
100 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
101 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
102 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
103 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
104 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
105 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
106 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
109 float IsFavorite(string srv)
115 srv = netaddress_resolve(srv, 26000);
118 p = crypto_getidfp(srv);
119 n = tokenize_console(cvar_string("net_slist_favorites"));
120 for(i = 0; i < n; ++i)
122 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
130 if(srv == netaddress_resolve(argv(i), 26000))
137 void ToggleFavorite(string srv)
139 string s, s0, s1, s2, srv_resolved, p;
141 srv_resolved = netaddress_resolve(srv, 26000);
142 p = crypto_getidfp(srv_resolved);
143 s = cvar_string("net_slist_favorites");
144 n = tokenize_console(s);
146 for(i = 0; i < n; ++i)
148 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
156 if(srv_resolved != netaddress_resolve(argv(i), 26000))
161 s0 = substring(s, 0, argv_end_index(i - 1));
163 s2 = substring(s, argv_start_index(i + 1), -1);
164 if(s0 != "" && s2 != "")
166 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
167 s = cvar_string("net_slist_favorites");
168 n = tokenize_console(s);
179 cvar_set("net_slist_favorites", strcat(s, s1, p));
181 cvar_set("net_slist_favorites", strcat(s, s1, srv));
187 void ServerList_Update_favoriteButton(entity btn, entity me)
189 if(IsFavorite(me.ipAddressBox.text))
190 me.favoriteButton.setText(me.favoriteButton, _("Remove"));
192 me.favoriteButton.setText(me.favoriteButton, _("Bookmark"));
195 entity makeXonoticServerList()
198 me = spawnXonoticServerList();
199 me.configureXonoticServerList(me);
202 void XonoticServerList_configureXonoticServerList(entity me)
204 me.configureXonoticListBox(me);
206 ServerList_UpdateFieldIDs();
210 void XonoticServerList_setSelected(entity me, float i)
213 save = me.selectedItem;
214 SUPER(XonoticServerList).setSelected(me, i);
216 if(me.selectedItem == save)
221 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
222 return; // sorry, it would be wrong
224 if(me.selectedServer)
225 strunzone(me.selectedServer);
226 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
228 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
229 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
230 me.ipAddressBoxFocused = -1;
232 void XonoticServerList_refreshServerList(entity me, float mode)
234 // 0: just reparametrize
235 // 1: also ask for new servers
237 //print("refresh of type ", ftos(mode), "\n");
238 /* if(mode == 2) // borken
241 localcmd("net_slist\n");
242 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
246 float m, o, i, n; // moin moin
247 string s, typestr, modstr;
250 m = strstrofs(s, ":", 0);
253 typestr = substring(s, 0, m);
254 s = substring(s, m + 1, strlen(s) - m - 1);
255 while(substring(s, 0, 1) == " ")
256 s = substring(s, 1, strlen(s) - 1);
261 modstr = cvar_string("menu_slist_modfilter");
263 m = SLIST_MASK_AND - 1;
264 resethostcachemasks();
266 // ping: reject negative ping (no idea why this happens in the first place, engine bug)
267 sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
270 if(!me.filterShowFull)
272 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
273 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
277 if(!me.filterShowEmpty)
278 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
280 // gametype filtering
282 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
287 if(substring(modstr, 0, 1) == "!")
288 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
290 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
294 n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
295 for(i = 0; i < n; ++i)
297 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
299 m = SLIST_MASK_OR - 1;
302 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
303 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
304 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
305 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
307 o = 2; // favorites first
308 if(me.currentSortOrder < 0)
309 o |= 1; // descending
310 sethostcachesort(me.currentSortField, o);
316 void XonoticServerList_focusEnter(entity me)
318 if(time < me.nextRefreshTime)
320 //print("sorry, no refresh yet\n");
323 me.nextRefreshTime = time + 10;
324 me.refreshServerList(me, 1);
326 void XonoticServerList_draw(entity me)
328 float i, found, owned;
330 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
334 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
337 if(me.currentSortField == -1)
339 me.setSortOrder(me, SLIST_FIELD_PING, +1);
340 me.refreshServerList(me, 2);
342 else if(me.needsRefresh == 1)
344 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
346 else if(me.needsRefresh == 2)
349 me.refreshServerList(me, 0);
352 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
354 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
356 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
357 me.infoButton.disabled = ((me.nItems == 0) || !owned);
358 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
361 if(me.selectedServer)
363 for(i = 0; i < me.nItems; ++i)
364 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
366 if(i != me.selectedItem)
368 me.lastClickedServer = -1;
378 if(me.selectedItem >= me.nItems)
379 me.selectedItem = me.nItems - 1;
380 if(me.selectedServer)
381 strunzone(me.selectedServer);
382 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
387 if(me.selectedServer != me.ipAddressBox.text)
389 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
390 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
391 me.ipAddressBoxFocused = -1;
395 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
397 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
398 ServerList_Update_favoriteButton(NULL, me);
399 me.ipAddressBoxFocused = me.ipAddressBox.focused;
402 SUPER(XonoticServerList).draw(me);
404 void ServerList_PingSort_Click(entity btn, entity me)
406 me.setSortOrder(me, SLIST_FIELD_PING, +1);
408 void ServerList_NameSort_Click(entity btn, entity me)
410 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
412 void ServerList_MapSort_Click(entity btn, entity me)
414 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
416 void ServerList_PlayerSort_Click(entity btn, entity me)
418 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
420 void ServerList_TypeSort_Click(entity btn, entity me)
425 m = strstrofs(s, ":", 0);
428 s = substring(s, 0, m);
429 while(substring(s, m+1, 1) == " ") // skip spaces
435 for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
437 t = MapInfo_Type_ToString(i);
439 if(t == "") // it repeats (default case)
442 // choose the first one
443 s = MapInfo_Type_ToString(1);
448 // the type was found
449 // choose the next one
450 s = MapInfo_Type_ToString(i * 2);
452 s = MapInfo_Type_ToString(1);
459 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
461 me.controlledTextbox.setText(me.controlledTextbox, s);
462 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
463 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
464 //ServerList_Filter_Change(me.controlledTextbox, me);
466 void ServerList_Filter_Change(entity box, entity me)
469 strunzone(me.filterString);
471 me.filterString = strzone(box.text);
473 me.filterString = string_null;
474 me.refreshServerList(me, 0);
476 me.ipAddressBox.setText(me.ipAddressBox, "");
477 me.ipAddressBox.cursorPos = 0;
478 me.ipAddressBoxFocused = -1;
480 void ServerList_ShowEmpty_Click(entity box, entity me)
482 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
483 me.refreshServerList(me, 0);
485 me.ipAddressBox.setText(me.ipAddressBox, "");
486 me.ipAddressBox.cursorPos = 0;
487 me.ipAddressBoxFocused = -1;
489 void ServerList_ShowFull_Click(entity box, entity me)
491 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
492 me.refreshServerList(me, 0);
494 me.ipAddressBox.setText(me.ipAddressBox, "");
495 me.ipAddressBox.cursorPos = 0;
496 me.ipAddressBoxFocused = -1;
498 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
500 if(me.currentSortField == fld)
501 direction = -me.currentSortOrder;
502 me.currentSortOrder = direction;
503 me.currentSortField = fld;
504 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
505 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
506 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
507 me.sortButton4.forcePressed = 0;
508 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
510 if(me.selectedServer)
511 strunzone(me.selectedServer);
512 me.selectedServer = string_null;
513 me.refreshServerList(me, 0);
515 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
517 vector originInLBSpace, sizeInLBSpace;
518 originInLBSpace = eY * (-me.itemHeight);
519 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
521 vector originInDialogSpace, sizeInDialogSpace;
522 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
523 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
525 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
526 btn.Container_size_x = sizeInDialogSpace_x * theSize;
527 btn.setText(btn, theTitle);
528 btn.onClick = theFunc;
529 btn.onClickEntity = me;
532 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
534 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
536 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
537 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
538 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
540 me.columnIconsOrigin = 0;
541 me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
542 me.columnPingSize = me.realFontSize_x * 3;
543 me.columnMapSize = me.realFontSize_x * 10;
544 me.columnTypeSize = me.realFontSize_x * 4;
545 me.columnPlayersSize = me.realFontSize_x * 5;
546 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
547 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
548 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
549 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
550 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
551 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
553 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
554 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
555 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
556 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
557 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
560 f = me.currentSortField;
563 me.currentSortField = -1;
564 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
567 void ServerList_Connect_Click(entity btn, entity me)
569 if(me.ipAddressBox.text == "")
570 localcmd("connect ", me.selectedServer, "\n");
572 localcmd("connect ", me.ipAddressBox.text, "\n");
574 void ServerList_Favorite_Click(entity btn, entity me)
577 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
580 ToggleFavorite(me.ipAddressBox.text);
581 me.ipAddressBoxFocused = -1;
584 void ServerList_Info_Click(entity btn, entity me)
586 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
587 DialogOpenButton_Click(me, main.serverInfoDialog);
589 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
591 if(i == me.lastClickedServer)
592 if(time < me.lastClickedTime + 0.3)
595 ServerList_Connect_Click(NULL, me);
597 me.lastClickedServer = i;
598 me.lastClickedTime = time;
600 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
602 // layout: Ping, Server name, Map name, NP, TP, MP
607 float m, pure, freeslots, j, sflags;
608 string s, typestr, versionstr, k, v, modname;
611 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
613 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
614 m = tokenizebyseparator(s, ":");
619 versionstr = argv(1);
625 for(j = 2; j < m; ++j)
629 k = substring(argv(j), 0, 1);
630 v = substring(argv(j), 1, -1);
641 #ifdef COMPAT_NO_MOD_IS_XONOTIC
647 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
648 s = gethostcachestring(SLIST_FIELD_MOD, i);
650 if(modname == "Xonotic")
654 // list the mods here on which the pure server check actually works
655 if(modname != "Xonotic")
656 if(modname != "MinstaGib")
659 if(modname != "NewToys")
662 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
663 theAlpha = SKINALPHA_SERVERLIST_FULL;
664 else if(freeslots == 0)
665 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
666 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
667 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
671 p = gethostcachenumber(SLIST_FIELD_PING, i);
674 #define PING_HIGH 500
676 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
677 else if(p < PING_MED)
678 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
679 else if(p < PING_HIGH)
681 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
682 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
687 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
690 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
692 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
693 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
696 s = gethostcachestring(SLIST_FIELD_CNAME, i);
699 if(substring(s, 0, 1) == "[")
704 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
710 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
711 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
713 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
714 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
719 if(cvar("crypto_aeslevel") >= 2)
724 if(cvar("crypto_aeslevel") >= 1)
734 // 2: AES recommended but not available
735 // 3: AES possible and will be used
736 // 4: AES recommended and will be used
740 vector iconSize = '0 0 0';
741 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
742 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
744 vector iconPos = '0 0 0';
745 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
746 iconPos_y = (1 - iconSize_y) * 0.5;
750 if not(me.seenIPv4 && me.seenIPv6)
752 iconPos_x += iconSize_x * 0.5;
754 else if(me.seenIPv4 && me.seenIPv6)
758 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
760 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
762 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
763 iconPos_x += iconSize_x;
768 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
769 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
771 iconPos_x += iconSize_x;
773 if(modname == "Xonotic")
777 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
778 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
783 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
784 if(draw_PictureSize(n) == '0 0 0')
785 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
787 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
789 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
791 iconPos_x += iconSize_x;
793 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
795 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
796 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
798 iconPos_x += iconSize_x;
802 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
803 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
804 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
805 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
806 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
807 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
808 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
809 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
810 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
813 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
818 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
819 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
821 if(scan == K_ENTER || scan == K_KP_ENTER)
823 ServerList_Connect_Click(NULL, me);
826 else if(scan == K_MOUSE2 || scan == K_SPACE)
830 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
831 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
836 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
841 ToggleFavorite(me.selectedServer);
842 me.ipAddressBoxFocused = -1;
847 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
849 else if(!me.controlledTextbox)
852 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);