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 void XonoticServerList_draw(entity me)
324 float i, found, owned;
326 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
330 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
333 if(me.currentSortField == -1)
335 me.setSortOrder(me, SLIST_FIELD_PING, +1);
336 me.refreshServerList(me, 2);
338 else if(me.needsRefresh == 1)
340 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
342 else if(me.needsRefresh == 2)
345 me.refreshServerList(me, 0);
348 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
350 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
352 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
353 me.infoButton.disabled = ((me.nItems == 0) || !owned);
354 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
357 if(me.selectedServer)
359 for(i = 0; i < me.nItems; ++i)
360 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
362 if(i != me.selectedItem)
364 me.lastClickedServer = -1;
374 if(me.selectedItem >= me.nItems)
375 me.selectedItem = me.nItems - 1;
376 if(me.selectedServer)
377 strunzone(me.selectedServer);
378 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
383 if(me.selectedServer != me.ipAddressBox.text)
385 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
386 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
387 me.ipAddressBoxFocused = -1;
391 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
393 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
394 ServerList_Update_favoriteButton(NULL, me);
395 me.ipAddressBoxFocused = me.ipAddressBox.focused;
398 SUPER(XonoticServerList).draw(me);
400 void ServerList_PingSort_Click(entity btn, entity me)
402 me.setSortOrder(me, SLIST_FIELD_PING, +1);
404 void ServerList_NameSort_Click(entity btn, entity me)
406 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
408 void ServerList_MapSort_Click(entity btn, entity me)
410 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
412 void ServerList_PlayerSort_Click(entity btn, entity me)
414 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
416 void ServerList_TypeSort_Click(entity btn, entity me)
421 m = strstrofs(s, ":", 0);
424 s = substring(s, 0, m);
425 while(substring(s, m+1, 1) == " ") // skip spaces
431 for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
433 t = MapInfo_Type_ToString(i);
435 if(t == "") // it repeats (default case)
438 // choose the first one
439 s = MapInfo_Type_ToString(1);
444 // the type was found
445 // choose the next one
446 s = MapInfo_Type_ToString(i * 2);
448 s = MapInfo_Type_ToString(1);
455 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
457 me.controlledTextbox.setText(me.controlledTextbox, s);
458 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
459 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
460 //ServerList_Filter_Change(me.controlledTextbox, me);
462 void ServerList_Filter_Change(entity box, entity me)
465 strunzone(me.filterString);
467 me.filterString = strzone(box.text);
469 me.filterString = string_null;
470 me.refreshServerList(me, 0);
472 me.ipAddressBox.setText(me.ipAddressBox, "");
473 me.ipAddressBox.cursorPos = 0;
474 me.ipAddressBoxFocused = -1;
476 void ServerList_ShowEmpty_Click(entity box, entity me)
478 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
479 me.refreshServerList(me, 0);
481 me.ipAddressBox.setText(me.ipAddressBox, "");
482 me.ipAddressBox.cursorPos = 0;
483 me.ipAddressBoxFocused = -1;
485 void ServerList_ShowFull_Click(entity box, entity me)
487 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
488 me.refreshServerList(me, 0);
490 me.ipAddressBox.setText(me.ipAddressBox, "");
491 me.ipAddressBox.cursorPos = 0;
492 me.ipAddressBoxFocused = -1;
494 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
496 if(me.currentSortField == fld)
497 direction = -me.currentSortOrder;
498 me.currentSortOrder = direction;
499 me.currentSortField = fld;
500 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
501 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
502 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
503 me.sortButton4.forcePressed = 0;
504 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
506 if(me.selectedServer)
507 strunzone(me.selectedServer);
508 me.selectedServer = string_null;
509 me.refreshServerList(me, 0);
511 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
513 vector originInLBSpace, sizeInLBSpace;
514 originInLBSpace = eY * (-me.itemHeight);
515 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
517 vector originInDialogSpace, sizeInDialogSpace;
518 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
519 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
521 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
522 btn.Container_size_x = sizeInDialogSpace_x * theSize;
523 btn.setText(btn, theTitle);
524 btn.onClick = theFunc;
525 btn.onClickEntity = me;
528 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
530 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
532 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
533 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
534 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
536 me.columnIconsOrigin = 0;
537 me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
538 me.columnPingSize = me.realFontSize_x * 3;
539 me.columnMapSize = me.realFontSize_x * 10;
540 me.columnTypeSize = me.realFontSize_x * 4;
541 me.columnPlayersSize = me.realFontSize_x * 5;
542 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
543 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
544 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
545 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
546 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
547 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
549 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
550 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
551 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
552 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
553 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
556 f = me.currentSortField;
559 me.currentSortField = -1;
560 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
563 void ServerList_Connect_Click(entity btn, entity me)
565 if(me.ipAddressBox.text == "")
566 localcmd("connect ", me.selectedServer, "\n");
568 localcmd("connect ", me.ipAddressBox.text, "\n");
570 void ServerList_Favorite_Click(entity btn, entity me)
573 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
576 ToggleFavorite(me.ipAddressBox.text);
577 me.ipAddressBoxFocused = -1;
580 void ServerList_Info_Click(entity btn, entity me)
582 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
583 DialogOpenButton_Click(me, main.serverInfoDialog);
585 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
587 if(i == me.lastClickedServer)
588 if(time < me.lastClickedTime + 0.3)
591 ServerList_Connect_Click(NULL, me);
593 me.lastClickedServer = i;
594 me.lastClickedTime = time;
596 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
598 // layout: Ping, Server name, Map name, NP, TP, MP
603 float m, pure, freeslots, j, sflags;
604 string s, typestr, versionstr, k, v, modname;
607 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
609 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
610 m = tokenizebyseparator(s, ":");
614 versionstr = argv(1);
619 for(j = 2; j < m; ++j)
623 k = substring(argv(j), 0, 1);
624 v = substring(argv(j), 1, -1);
635 #ifdef COMPAT_NO_MOD_IS_XONOTIC
641 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
642 s = gethostcachestring(SLIST_FIELD_MOD, i);
644 if(modname == "Xonotic")
648 // list the mods here on which the pure server check actually works
649 if(modname != "Xonotic")
650 if(modname != "MinstaGib")
653 if(modname != "NewToys")
656 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
657 theAlpha = SKINALPHA_SERVERLIST_FULL;
658 else if(freeslots == 0)
659 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
660 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
661 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
665 p = gethostcachenumber(SLIST_FIELD_PING, i);
668 #define PING_HIGH 500
670 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
671 else if(p < PING_MED)
672 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
673 else if(p < PING_HIGH)
675 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
676 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
681 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
684 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
686 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
687 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
690 s = gethostcachestring(SLIST_FIELD_CNAME, i);
693 if(substring(s, 0, 1) == "[")
698 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
704 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
705 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
707 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
708 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
713 if(cvar("crypto_aeslevel") >= 2)
718 if(cvar("crypto_aeslevel") >= 1)
728 // 2: AES recommended but not available
729 // 3: AES possible and will be used
730 // 4: AES recommended and will be used
735 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
736 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
739 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
740 iconPos_y = (1 - iconSize_y) * 0.5;
744 if not(me.seenIPv4 && me.seenIPv6)
746 iconPos_x += iconSize_x * 0.5;
748 else if(me.seenIPv4 && me.seenIPv6)
752 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
754 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
756 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
757 iconPos_x += iconSize_x;
762 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
763 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
765 iconPos_x += iconSize_x;
767 if(modname == "Xonotic")
771 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
772 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
777 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
778 if(draw_PictureSize(n) == '0 0 0')
779 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
781 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
783 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
785 iconPos_x += iconSize_x;
787 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
789 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
790 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
792 iconPos_x += iconSize_x;
796 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
797 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
798 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
799 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
800 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
801 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
802 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
803 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
804 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
807 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
812 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
813 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
815 if(scan == K_ENTER || scan == K_KP_ENTER)
817 ServerList_Connect_Click(NULL, me);
820 else if(scan == K_MOUSE2 || scan == K_SPACE)
824 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
825 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
828 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
833 ToggleFavorite(me.selectedServer);
834 me.ipAddressBoxFocused = -1;
837 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
839 else if(!me.controlledTextbox)
842 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);