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)
292 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
294 m = SLIST_MASK_OR - 1;
297 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
298 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
299 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
300 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
302 o = 2; // favorites first
303 if(me.currentSortOrder < 0)
304 o |= 1; // descending
305 sethostcachesort(me.currentSortField, o);
311 void XonoticServerList_focusEnter(entity me)
313 if(time < me.nextRefreshTime)
315 //print("sorry, no refresh yet\n");
318 me.nextRefreshTime = time + 10;
319 me.refreshServerList(me, 1);
321 void XonoticServerList_draw(entity me)
323 float i, found, owned;
325 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
329 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
332 if(me.currentSortField == -1)
334 me.setSortOrder(me, SLIST_FIELD_PING, +1);
335 me.refreshServerList(me, 2);
337 else if(me.needsRefresh == 1)
339 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
341 else if(me.needsRefresh == 2)
344 me.refreshServerList(me, 0);
347 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
349 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
351 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
352 me.infoButton.disabled = ((me.nItems == 0) || !owned);
353 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
356 if(me.selectedServer)
358 for(i = 0; i < me.nItems; ++i)
359 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
361 if(i != me.selectedItem)
363 me.lastClickedServer = -1;
373 if(me.selectedItem >= me.nItems)
374 me.selectedItem = me.nItems - 1;
375 if(me.selectedServer)
376 strunzone(me.selectedServer);
377 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
382 if(me.selectedServer != me.ipAddressBox.text)
384 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
385 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
386 me.ipAddressBoxFocused = -1;
390 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
392 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
393 ServerList_Update_favoriteButton(NULL, me);
394 me.ipAddressBoxFocused = me.ipAddressBox.focused;
397 SUPER(XonoticServerList).draw(me);
399 void ServerList_PingSort_Click(entity btn, entity me)
401 me.setSortOrder(me, SLIST_FIELD_PING, +1);
403 void ServerList_NameSort_Click(entity btn, entity me)
405 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
407 void ServerList_MapSort_Click(entity btn, entity me)
409 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
411 void ServerList_PlayerSort_Click(entity btn, entity me)
413 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
415 void ServerList_TypeSort_Click(entity btn, entity me)
420 m = strstrofs(s, ":", 0);
423 s = substring(s, 0, m);
424 while(substring(s, m+1, 1) == " ") // skip spaces
430 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
432 t = GametypeNameFromType(i);
434 if(t == GametypeNameFromType(0)) // it repeats (default case)
437 // choose the first one
441 if(s == GametypeNameFromType(i))
443 // the type was found
444 // choose the next one
445 s = GametypeNameFromType(i + 1);
446 if(s == GametypeNameFromType(0))
454 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
456 me.controlledTextbox.setText(me.controlledTextbox, s);
457 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
458 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
459 //ServerList_Filter_Change(me.controlledTextbox, me);
461 void ServerList_Filter_Change(entity box, entity me)
464 strunzone(me.filterString);
466 me.filterString = strzone(box.text);
468 me.filterString = string_null;
469 me.refreshServerList(me, 0);
471 me.ipAddressBox.setText(me.ipAddressBox, "");
472 me.ipAddressBox.cursorPos = 0;
473 me.ipAddressBoxFocused = -1;
475 void ServerList_ShowEmpty_Click(entity box, entity me)
477 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
478 me.refreshServerList(me, 0);
480 me.ipAddressBox.setText(me.ipAddressBox, "");
481 me.ipAddressBox.cursorPos = 0;
482 me.ipAddressBoxFocused = -1;
484 void ServerList_ShowFull_Click(entity box, entity me)
486 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
487 me.refreshServerList(me, 0);
489 me.ipAddressBox.setText(me.ipAddressBox, "");
490 me.ipAddressBox.cursorPos = 0;
491 me.ipAddressBoxFocused = -1;
493 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
495 if(me.currentSortField == fld)
496 direction = -me.currentSortOrder;
497 me.currentSortOrder = direction;
498 me.currentSortField = fld;
499 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
500 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
501 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
502 me.sortButton4.forcePressed = 0;
503 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
505 if(me.selectedServer)
506 strunzone(me.selectedServer);
507 me.selectedServer = string_null;
508 me.refreshServerList(me, 0);
510 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
512 vector originInLBSpace, sizeInLBSpace;
513 originInLBSpace = eY * (-me.itemHeight);
514 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
516 vector originInDialogSpace, sizeInDialogSpace;
517 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
518 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
520 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
521 btn.Container_size_x = sizeInDialogSpace_x * theSize;
522 btn.setText(btn, theTitle);
523 btn.onClick = theFunc;
524 btn.onClickEntity = me;
527 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
529 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
531 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
532 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
533 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
535 me.columnIconsOrigin = 0;
536 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
537 me.columnPingSize = me.realFontSize_x * 3;
538 me.columnMapSize = me.realFontSize_x * 10;
539 me.columnTypeSize = me.realFontSize_x * 4;
540 me.columnPlayersSize = me.realFontSize_x * 5;
541 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
542 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
543 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
544 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
545 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
546 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
548 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
549 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
550 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
551 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
552 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
555 f = me.currentSortField;
558 me.currentSortField = -1;
559 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
562 void ServerList_Connect_Click(entity btn, entity me)
564 if(me.ipAddressBox.text == "")
565 localcmd("connect ", me.selectedServer, "\n");
567 localcmd("connect ", me.ipAddressBox.text, "\n");
569 void ServerList_Favorite_Click(entity btn, entity me)
572 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
575 ToggleFavorite(me.ipAddressBox.text);
576 me.ipAddressBoxFocused = -1;
579 void ServerList_Info_Click(entity btn, entity me)
581 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
582 DialogOpenButton_Click(me, main.serverInfoDialog);
584 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
586 if(i == me.lastClickedServer)
587 if(time < me.lastClickedTime + 0.3)
590 ServerList_Connect_Click(NULL, me);
592 me.lastClickedServer = i;
593 me.lastClickedTime = time;
595 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
597 // layout: Ping, Server name, Map name, NP, TP, MP
605 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
607 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
608 theAlpha = SKINALPHA_SERVERLIST_FULL;
609 else if(strstrofs(gethostcachestring(SLIST_FIELD_QCSTATUS, i), ":S0:", 0) >= 0)
610 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
611 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
612 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
616 p = gethostcachenumber(SLIST_FIELD_PING, i);
619 #define PING_HIGH 500
621 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
622 else if(p < PING_MED)
623 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
624 else if(p < PING_HIGH)
626 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
627 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
632 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
635 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
637 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
638 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
641 s = gethostcachestring(SLIST_FIELD_CNAME, i);
644 if(substring(s, 0, 1) == "[")
649 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
655 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
656 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
658 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
659 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
664 if(cvar("crypto_aeslevel") >= 2)
669 if(cvar("crypto_aeslevel") >= 1)
679 // 2: AES recommended but not available
680 // 3: AES possible and will be used
681 // 4: AES recommended and will be used
684 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
687 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
688 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
691 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
692 iconPos_y = (1 - iconSize_y) * 0.5;
694 if not(me.seenIPv4 && me.seenIPv6)
696 iconPos_x += iconSize_x * 0.5;
698 else if(me.seenIPv4 && me.seenIPv6)
701 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
703 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
704 iconPos_x += iconSize_x;
707 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
708 iconPos_x += iconSize_x;
710 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
711 iconPos_x += iconSize_x;
715 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
716 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
717 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
718 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
719 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
720 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
721 p = strstrofs(s, ":", 0);
723 s = substring(s, 0, p);
726 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
727 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
728 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
729 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
732 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
737 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
738 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
740 if(scan == K_ENTER || scan == K_KP_ENTER)
742 ServerList_Connect_Click(NULL, me);
745 else if(scan == K_MOUSE2 || scan == K_SPACE)
749 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
750 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
753 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
758 ToggleFavorite(me.selectedServer);
759 me.ipAddressBoxFocused = -1;
762 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
764 else if(!me.controlledTextbox)
767 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);