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, ":");
615 versionstr = argv(1);
621 for(j = 2; j < m; ++j)
625 k = substring(argv(j), 0, 1);
626 v = substring(argv(j), 1, -1);
637 #ifdef COMPAT_NO_MOD_IS_XONOTIC
643 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
644 s = gethostcachestring(SLIST_FIELD_MOD, i);
646 if(modname == "Xonotic")
650 // list the mods here on which the pure server check actually works
651 if(modname != "Xonotic")
652 if(modname != "MinstaGib")
655 if(modname != "NewToys")
658 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
659 theAlpha = SKINALPHA_SERVERLIST_FULL;
660 else if(freeslots == 0)
661 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
662 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
663 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
667 p = gethostcachenumber(SLIST_FIELD_PING, i);
670 #define PING_HIGH 500
672 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
673 else if(p < PING_MED)
674 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
675 else if(p < PING_HIGH)
677 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
678 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
683 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
686 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
688 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
689 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
692 s = gethostcachestring(SLIST_FIELD_CNAME, i);
695 if(substring(s, 0, 1) == "[")
700 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
706 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
707 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
709 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
710 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
715 if(cvar("crypto_aeslevel") >= 2)
720 if(cvar("crypto_aeslevel") >= 1)
730 // 2: AES recommended but not available
731 // 3: AES possible and will be used
732 // 4: AES recommended and will be used
737 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
738 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
741 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
742 iconPos_y = (1 - iconSize_y) * 0.5;
746 if not(me.seenIPv4 && me.seenIPv6)
748 iconPos_x += iconSize_x * 0.5;
750 else if(me.seenIPv4 && me.seenIPv6)
754 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
756 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
758 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
759 iconPos_x += iconSize_x;
764 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
765 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
767 iconPos_x += iconSize_x;
769 if(modname == "Xonotic")
773 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
774 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
779 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
780 if(draw_PictureSize(n) == '0 0 0')
781 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
783 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
785 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
787 iconPos_x += iconSize_x;
789 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
791 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
792 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
794 iconPos_x += iconSize_x;
798 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
799 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
800 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
801 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
802 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
803 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
804 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
805 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
806 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
809 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
814 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
815 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
817 if(scan == K_ENTER || scan == K_KP_ENTER)
819 ServerList_Connect_Click(NULL, me);
822 else if(scan == K_MOUSE2 || scan == K_SPACE)
826 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
827 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
830 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
835 ToggleFavorite(me.selectedServer);
836 me.ipAddressBoxFocused = -1;
839 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
841 else if(!me.controlledTextbox)
844 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);