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
241 float m, o, i, n; // moin moin
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);
265 if(!me.filterShowFull)
267 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
268 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
272 if(!me.filterShowEmpty)
273 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
275 // gametype filtering
277 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
282 if(substring(modstr, 0, 1) == "!")
283 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
285 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
289 n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
290 for(i = 0; i < n; ++i)
291 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTEQUAL);
293 m = SLIST_MASK_OR - 1;
296 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
297 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
298 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
299 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
301 o = 2; // favorites first
302 if(me.currentSortOrder < 0)
303 o |= 1; // descending
304 sethostcachesort(me.currentSortField, o);
310 void XonoticServerList_focusEnter(entity me)
312 if(time < me.nextRefreshTime)
314 //print("sorry, no refresh yet\n");
317 me.nextRefreshTime = time + 10;
318 me.refreshServerList(me, 1);
320 void XonoticServerList_draw(entity me)
322 float i, found, owned;
324 if(me.currentSortField == -1)
326 me.setSortOrder(me, SLIST_FIELD_PING, +1);
327 me.refreshServerList(me, 2);
329 else if(me.needsRefresh == 1)
331 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
333 else if(me.needsRefresh == 2)
336 me.refreshServerList(me, 0);
339 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
341 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
343 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
344 me.infoButton.disabled = ((me.nItems == 0) || !owned);
345 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
348 if(me.selectedServer)
350 for(i = 0; i < me.nItems; ++i)
351 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
353 if(i != me.selectedItem)
355 me.lastClickedServer = -1;
365 if(me.selectedItem >= me.nItems)
366 me.selectedItem = me.nItems - 1;
367 if(me.selectedServer)
368 strunzone(me.selectedServer);
369 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
374 if(me.selectedServer != me.ipAddressBox.text)
376 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
377 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
378 me.ipAddressBoxFocused = -1;
382 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
384 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
385 ServerList_Update_favoriteButton(NULL, me);
386 me.ipAddressBoxFocused = me.ipAddressBox.focused;
389 SUPER(XonoticServerList).draw(me);
391 void ServerList_PingSort_Click(entity btn, entity me)
393 me.setSortOrder(me, SLIST_FIELD_PING, +1);
395 void ServerList_NameSort_Click(entity btn, entity me)
397 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
399 void ServerList_MapSort_Click(entity btn, entity me)
401 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
403 void ServerList_PlayerSort_Click(entity btn, entity me)
405 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
407 void ServerList_TypeSort_Click(entity btn, entity me)
412 m = strstrofs(s, ":", 0);
415 s = substring(s, 0, m);
416 while(substring(s, m+1, 1) == " ") // skip spaces
422 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
424 t = GametypeNameFromType(i);
426 if(t == GametypeNameFromType(0)) // it repeats (default case)
429 // choose the first one
433 if(s == GametypeNameFromType(i))
435 // the type was found
436 // choose the next one
437 s = GametypeNameFromType(i + 1);
438 if(s == GametypeNameFromType(0))
446 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
448 me.controlledTextbox.setText(me.controlledTextbox, s);
449 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
450 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
451 //ServerList_Filter_Change(me.controlledTextbox, me);
453 void ServerList_Filter_Change(entity box, entity me)
456 strunzone(me.filterString);
458 me.filterString = strzone(box.text);
460 me.filterString = string_null;
461 me.refreshServerList(me, 0);
463 me.ipAddressBox.setText(me.ipAddressBox, "");
464 me.ipAddressBox.cursorPos = 0;
465 me.ipAddressBoxFocused = -1;
467 void ServerList_ShowEmpty_Click(entity box, entity me)
469 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
470 me.refreshServerList(me, 0);
472 me.ipAddressBox.setText(me.ipAddressBox, "");
473 me.ipAddressBox.cursorPos = 0;
474 me.ipAddressBoxFocused = -1;
476 void ServerList_ShowFull_Click(entity box, entity me)
478 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
479 me.refreshServerList(me, 0);
481 me.ipAddressBox.setText(me.ipAddressBox, "");
482 me.ipAddressBox.cursorPos = 0;
483 me.ipAddressBoxFocused = -1;
485 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
487 if(me.currentSortField == fld)
488 direction = -me.currentSortOrder;
489 me.currentSortOrder = direction;
490 me.currentSortField = fld;
491 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
492 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
493 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
494 me.sortButton4.forcePressed = 0;
495 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
497 if(me.selectedServer)
498 strunzone(me.selectedServer);
499 me.selectedServer = string_null;
500 me.refreshServerList(me, 0);
502 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
504 vector originInLBSpace, sizeInLBSpace;
505 originInLBSpace = eY * (-me.itemHeight);
506 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
508 vector originInDialogSpace, sizeInDialogSpace;
509 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
510 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
512 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
513 btn.Container_size_x = sizeInDialogSpace_x * theSize;
514 btn.setText(btn, theTitle);
515 btn.onClick = theFunc;
516 btn.onClickEntity = me;
519 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
521 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
523 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
524 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
525 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
527 me.columnIconsOrigin = 0;
528 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
529 me.columnPingSize = me.realFontSize_x * 3;
530 me.columnMapSize = me.realFontSize_x * 10;
531 me.columnTypeSize = me.realFontSize_x * 4;
532 me.columnPlayersSize = me.realFontSize_x * 5;
533 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
534 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
535 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
536 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
537 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
538 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
540 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
541 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
542 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
543 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
544 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
547 f = me.currentSortField;
550 me.currentSortField = -1;
551 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
554 void ServerList_Connect_Click(entity btn, entity me)
556 if(me.ipAddressBox.text == "")
557 localcmd("connect ", me.selectedServer, "\n");
559 localcmd("connect ", me.ipAddressBox.text, "\n");
561 void ServerList_Favorite_Click(entity btn, entity me)
564 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
567 ToggleFavorite(me.ipAddressBox.text);
568 me.ipAddressBoxFocused = -1;
571 void ServerList_Info_Click(entity btn, entity me)
573 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
574 DialogOpenButton_Click(me, main.serverInfoDialog);
576 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
578 if(i == me.lastClickedServer)
579 if(time < me.lastClickedTime + 0.3)
582 ServerList_Connect_Click(NULL, me);
584 me.lastClickedServer = i;
585 me.lastClickedTime = time;
587 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
589 // layout: Ping, Server name, Map name, NP, TP, MP
597 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
599 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
600 theAlpha = SKINALPHA_SERVERLIST_FULL;
601 else if(strstrofs(gethostcachestring(SLIST_FIELD_QCSTATUS, i), ":S0:", 0) >= 0)
602 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
603 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
604 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
608 p = gethostcachenumber(SLIST_FIELD_PING, i);
611 #define PING_HIGH 500
613 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
614 else if(p < PING_MED)
615 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
616 else if(p < PING_HIGH)
618 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
619 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
624 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
627 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
629 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
630 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
633 s = gethostcachestring(SLIST_FIELD_CNAME, i);
636 if(substring(s, 0, 1) == "[")
641 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
647 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
648 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
650 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
651 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
656 if(cvar("crypto_aeslevel") >= 2)
661 if(cvar("crypto_aeslevel") >= 1)
671 // 2: AES recommended but not available
672 // 3: AES possible and will be used
673 // 4: AES recommended and will be used
676 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
679 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
680 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
683 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
684 iconPos_y = (1 - iconSize_y) * 0.5;
686 if not(me.seenIPv4 && me.seenIPv6)
688 iconPos_x += iconSize_x * 0.5;
690 else if(me.seenIPv4 && me.seenIPv6)
693 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
695 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
696 iconPos_x += iconSize_x;
699 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
700 iconPos_x += iconSize_x;
702 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
703 iconPos_x += iconSize_x;
707 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
708 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
709 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
710 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
711 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
712 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
713 p = strstrofs(s, ":", 0);
715 s = substring(s, 0, p);
718 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
719 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
720 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
721 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
724 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
729 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
730 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
732 if(scan == K_ENTER || scan == K_KP_ENTER)
734 ServerList_Connect_Click(NULL, me);
737 else if(scan == K_MOUSE2 || scan == K_SPACE)
741 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
742 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
745 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
750 ToggleFavorite(me.selectedServer);
751 me.ipAddressBoxFocused = -1;
754 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
756 else if(!me.controlledTextbox)
759 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);