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);
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;
85 void ServerList_UpdateFieldIDs()
87 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
88 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
89 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
90 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
91 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
92 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
93 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
94 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
95 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
96 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
97 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
98 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
99 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
100 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
101 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
104 float IsFavorite(string srv)
110 srv = netaddress_resolve(srv, 26000);
113 p = crypto_getidfp(srv);
114 n = tokenize_console(cvar_string("net_slist_favorites"));
115 for(i = 0; i < n; ++i)
117 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
125 if(srv == netaddress_resolve(argv(i), 26000))
132 void ToggleFavorite(string srv)
134 string s, s0, s1, s2, srv_resolved, p;
136 srv_resolved = netaddress_resolve(srv, 26000);
137 p = crypto_getidfp(srv_resolved);
138 s = cvar_string("net_slist_favorites");
139 n = tokenize_console(s);
141 for(i = 0; i < n; ++i)
143 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
151 if(srv_resolved != netaddress_resolve(argv(i), 26000))
156 s0 = substring(s, 0, argv_end_index(i - 1));
158 s2 = substring(s, argv_start_index(i + 1), -1);
159 if(s0 != "" && s2 != "")
161 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
162 s = cvar_string("net_slist_favorites");
163 n = tokenize_console(s);
174 cvar_set("net_slist_favorites", strcat(s, s1, p));
176 cvar_set("net_slist_favorites", strcat(s, s1, srv));
182 void ServerList_Update_favoriteButton(entity btn, entity me)
184 if(IsFavorite(me.ipAddressBox.text))
185 me.favoriteButton.setText(me.favoriteButton, _("Remove"));
187 me.favoriteButton.setText(me.favoriteButton, _("Bookmark"));
190 entity makeXonoticServerList()
193 me = spawnXonoticServerList();
194 me.configureXonoticServerList(me);
197 void XonoticServerList_configureXonoticServerList(entity me)
199 me.configureXonoticListBox(me);
201 ServerList_UpdateFieldIDs();
205 void XonoticServerList_setSelected(entity me, float i)
208 save = me.selectedItem;
209 SUPER(XonoticServerList).setSelected(me, i);
211 if(me.selectedItem == save)
216 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
217 return; // sorry, it would be wrong
219 if(me.selectedServer)
220 strunzone(me.selectedServer);
221 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
223 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
224 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
225 me.ipAddressBoxFocused = -1;
227 void XonoticServerList_refreshServerList(entity me, float mode)
229 // 0: just reparametrize
230 // 1: also ask for new servers
232 //print("refresh of type ", ftos(mode), "\n");
233 /* if(mode == 2) // borken
236 localcmd("net_slist\n");
237 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
242 string s, typestr, modstr;
245 m = strstrofs(s, ":", 0);
248 typestr = substring(s, 0, m);
249 s = substring(s, m + 1, strlen(s) - m - 1);
250 while(substring(s, 0, 1) == " ")
251 s = substring(s, 1, strlen(s) - 1);
256 modstr = cvar_string("menu_slist_modfilter");
258 m = SLIST_MASK_AND - 1;
259 resethostcachemasks();
261 // ping: reject negative ping (no idea why this happens in the first place, engine bug)
262 sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
264 if(!me.filterShowFull)
266 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
267 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
269 if(!me.filterShowEmpty)
270 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
272 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
275 if(substring(modstr, 0, 1) == "!")
276 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
278 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
280 m = SLIST_MASK_OR - 1;
283 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
284 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
285 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
286 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
288 o = 2; // favorites first
289 if(me.currentSortOrder < 0)
290 o |= 1; // descending
291 sethostcachesort(me.currentSortField, o);
297 void XonoticServerList_focusEnter(entity me)
299 if(time < me.nextRefreshTime)
301 //print("sorry, no refresh yet\n");
304 me.nextRefreshTime = time + 10;
305 me.refreshServerList(me, 1);
307 void XonoticServerList_draw(entity me)
309 float i, found, owned;
311 if(me.currentSortField == -1)
313 me.setSortOrder(me, SLIST_FIELD_PING, +1);
314 me.refreshServerList(me, 2);
316 else if(me.needsRefresh == 1)
318 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
320 else if(me.needsRefresh == 2)
323 me.refreshServerList(me, 0);
326 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
328 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
330 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
331 me.infoButton.disabled = ((me.nItems == 0) || !owned);
332 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
335 if(me.selectedServer)
337 for(i = 0; i < me.nItems; ++i)
338 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
340 if(i != me.selectedItem)
342 me.lastClickedServer = -1;
352 if(me.selectedItem >= me.nItems)
353 me.selectedItem = me.nItems - 1;
354 if(me.selectedServer)
355 strunzone(me.selectedServer);
356 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
361 if(me.selectedServer != me.ipAddressBox.text)
363 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
364 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
365 me.ipAddressBoxFocused = -1;
369 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
371 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
372 ServerList_Update_favoriteButton(NULL, me);
373 me.ipAddressBoxFocused = me.ipAddressBox.focused;
376 SUPER(XonoticServerList).draw(me);
378 void ServerList_PingSort_Click(entity btn, entity me)
380 me.setSortOrder(me, SLIST_FIELD_PING, +1);
382 void ServerList_NameSort_Click(entity btn, entity me)
384 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
386 void ServerList_MapSort_Click(entity btn, entity me)
388 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
390 void ServerList_PlayerSort_Click(entity btn, entity me)
392 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
394 void ServerList_TypeSort_Click(entity btn, entity me)
399 m = strstrofs(s, ":", 0);
402 s = substring(s, 0, m);
403 while(substring(s, m+1, 1) == " ") // skip spaces
409 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
411 t = GametypeNameFromType(i);
413 if(t == GametypeNameFromType(0)) // it repeats (default case)
416 // choose the first one
420 if(s == GametypeNameFromType(i))
422 // the type was found
423 // choose the next one
424 s = GametypeNameFromType(i + 1);
425 if(s == GametypeNameFromType(0))
433 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
435 me.controlledTextbox.setText(me.controlledTextbox, s);
436 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
437 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
438 //ServerList_Filter_Change(me.controlledTextbox, me);
440 void ServerList_Filter_Change(entity box, entity me)
443 strunzone(me.filterString);
445 me.filterString = strzone(box.text);
447 me.filterString = string_null;
448 me.refreshServerList(me, 0);
450 me.ipAddressBox.setText(me.ipAddressBox, "");
451 me.ipAddressBox.cursorPos = 0;
452 me.ipAddressBoxFocused = -1;
454 void ServerList_ShowEmpty_Click(entity box, entity me)
456 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
457 me.refreshServerList(me, 0);
459 me.ipAddressBox.setText(me.ipAddressBox, "");
460 me.ipAddressBox.cursorPos = 0;
461 me.ipAddressBoxFocused = -1;
463 void ServerList_ShowFull_Click(entity box, entity me)
465 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
466 me.refreshServerList(me, 0);
468 me.ipAddressBox.setText(me.ipAddressBox, "");
469 me.ipAddressBox.cursorPos = 0;
470 me.ipAddressBoxFocused = -1;
472 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
474 if(me.currentSortField == fld)
475 direction = -me.currentSortOrder;
476 me.currentSortOrder = direction;
477 me.currentSortField = fld;
478 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
479 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
480 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
481 me.sortButton4.forcePressed = 0;
482 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
484 if(me.selectedServer)
485 strunzone(me.selectedServer);
486 me.selectedServer = string_null;
487 me.refreshServerList(me, 0);
489 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
491 vector originInLBSpace, sizeInLBSpace;
492 originInLBSpace = eY * (-me.itemHeight);
493 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
495 vector originInDialogSpace, sizeInDialogSpace;
496 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
497 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
499 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
500 btn.Container_size_x = sizeInDialogSpace_x * theSize;
501 btn.setText(btn, theTitle);
502 btn.onClick = theFunc;
503 btn.onClickEntity = me;
506 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
508 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
510 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
511 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
512 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
514 me.columnIconsOrigin = 0;
515 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
516 me.columnPingSize = me.realFontSize_x * 3;
517 me.columnMapSize = me.realFontSize_x * 10;
518 me.columnTypeSize = me.realFontSize_x * 4;
519 me.columnPlayersSize = me.realFontSize_x * 5;
520 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
521 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
522 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
523 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
524 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
525 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
527 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
528 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
529 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
530 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
531 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
534 f = me.currentSortField;
537 me.currentSortField = -1;
538 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
541 void ServerList_Connect_Click(entity btn, entity me)
543 if(me.ipAddressBox.text == "")
544 localcmd("connect ", me.selectedServer, "\n");
546 localcmd("connect ", me.ipAddressBox.text, "\n");
548 void ServerList_Favorite_Click(entity btn, entity me)
551 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
554 ToggleFavorite(me.ipAddressBox.text);
555 me.ipAddressBoxFocused = -1;
558 void ServerList_Info_Click(entity btn, entity me)
560 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
561 DialogOpenButton_Click(me, main.serverInfoDialog);
563 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
565 if(i == me.lastClickedServer)
566 if(time < me.lastClickedTime + 0.3)
569 ServerList_Connect_Click(NULL, me);
571 me.lastClickedServer = i;
572 me.lastClickedTime = time;
574 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
576 // layout: Ping, Server name, Map name, NP, TP, MP
584 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
586 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
587 theAlpha = SKINALPHA_SERVERLIST_FULL;
588 else if(strstrofs(gethostcachestring(SLIST_FIELD_QCSTATUS, i), ":S0:", 0) >= 0)
589 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
590 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
591 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
595 p = gethostcachenumber(SLIST_FIELD_PING, i);
598 #define PING_HIGH 500
600 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
601 else if(p < PING_MED)
602 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
603 else if(p < PING_HIGH)
605 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
606 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
611 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
614 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
616 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
617 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
620 s = gethostcachestring(SLIST_FIELD_CNAME, i);
623 if(substring(s, 0, 1) == "[")
628 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
634 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
635 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
637 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
638 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
643 if(cvar("crypto_aeslevel") >= 2)
648 if(cvar("crypto_aeslevel") >= 1)
658 // 2: AES recommended but not available
659 // 3: AES possible and will be used
660 // 4: AES recommended and will be used
663 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
666 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
667 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
670 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
671 iconPos_y = (1 - iconSize_y) * 0.5;
673 if not(me.seenIPv4 && me.seenIPv6)
675 iconPos_x += iconSize_x * 0.5;
677 else if(me.seenIPv4 && me.seenIPv6)
680 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
682 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
683 iconPos_x += iconSize_x;
686 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
687 iconPos_x += iconSize_x;
689 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
690 iconPos_x += iconSize_x;
694 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
695 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
696 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
697 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
698 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
699 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
700 p = strstrofs(s, ":", 0);
702 s = substring(s, 0, p);
705 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
706 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
707 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
708 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
711 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
716 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
717 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
719 if(scan == K_ENTER || scan == K_KP_ENTER)
721 ServerList_Connect_Click(NULL, me);
724 else if(scan == K_MOUSE2 || scan == K_SPACE)
728 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
729 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
732 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
737 ToggleFavorite(me.selectedServer);
738 me.ipAddressBoxFocused = -1;
741 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
743 else if(!me.controlledTextbox)
746 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);