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(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
328 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
331 if(me.currentSortField == -1)
333 me.setSortOrder(me, SLIST_FIELD_PING, +1);
334 me.refreshServerList(me, 2);
336 else if(me.needsRefresh == 1)
338 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
340 else if(me.needsRefresh == 2)
343 me.refreshServerList(me, 0);
346 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
348 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
350 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
351 me.infoButton.disabled = ((me.nItems == 0) || !owned);
352 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
355 if(me.selectedServer)
357 for(i = 0; i < me.nItems; ++i)
358 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
360 if(i != me.selectedItem)
362 me.lastClickedServer = -1;
372 if(me.selectedItem >= me.nItems)
373 me.selectedItem = me.nItems - 1;
374 if(me.selectedServer)
375 strunzone(me.selectedServer);
376 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
381 if(me.selectedServer != me.ipAddressBox.text)
383 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
384 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
385 me.ipAddressBoxFocused = -1;
389 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
391 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
392 ServerList_Update_favoriteButton(NULL, me);
393 me.ipAddressBoxFocused = me.ipAddressBox.focused;
396 SUPER(XonoticServerList).draw(me);
398 void ServerList_PingSort_Click(entity btn, entity me)
400 me.setSortOrder(me, SLIST_FIELD_PING, +1);
402 void ServerList_NameSort_Click(entity btn, entity me)
404 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
406 void ServerList_MapSort_Click(entity btn, entity me)
408 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
410 void ServerList_PlayerSort_Click(entity btn, entity me)
412 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
414 void ServerList_TypeSort_Click(entity btn, entity me)
419 m = strstrofs(s, ":", 0);
422 s = substring(s, 0, m);
423 while(substring(s, m+1, 1) == " ") // skip spaces
429 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
431 t = GametypeNameFromType(i);
433 if(t == GametypeNameFromType(0)) // it repeats (default case)
436 // choose the first one
440 if(s == GametypeNameFromType(i))
442 // the type was found
443 // choose the next one
444 s = GametypeNameFromType(i + 1);
445 if(s == GametypeNameFromType(0))
453 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
455 me.controlledTextbox.setText(me.controlledTextbox, s);
456 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
457 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
458 //ServerList_Filter_Change(me.controlledTextbox, me);
460 void ServerList_Filter_Change(entity box, entity me)
463 strunzone(me.filterString);
465 me.filterString = strzone(box.text);
467 me.filterString = string_null;
468 me.refreshServerList(me, 0);
470 me.ipAddressBox.setText(me.ipAddressBox, "");
471 me.ipAddressBox.cursorPos = 0;
472 me.ipAddressBoxFocused = -1;
474 void ServerList_ShowEmpty_Click(entity box, entity me)
476 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
477 me.refreshServerList(me, 0);
479 me.ipAddressBox.setText(me.ipAddressBox, "");
480 me.ipAddressBox.cursorPos = 0;
481 me.ipAddressBoxFocused = -1;
483 void ServerList_ShowFull_Click(entity box, entity me)
485 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
486 me.refreshServerList(me, 0);
488 me.ipAddressBox.setText(me.ipAddressBox, "");
489 me.ipAddressBox.cursorPos = 0;
490 me.ipAddressBoxFocused = -1;
492 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
494 if(me.currentSortField == fld)
495 direction = -me.currentSortOrder;
496 me.currentSortOrder = direction;
497 me.currentSortField = fld;
498 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
499 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
500 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
501 me.sortButton4.forcePressed = 0;
502 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
504 if(me.selectedServer)
505 strunzone(me.selectedServer);
506 me.selectedServer = string_null;
507 me.refreshServerList(me, 0);
509 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
511 vector originInLBSpace, sizeInLBSpace;
512 originInLBSpace = eY * (-me.itemHeight);
513 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
515 vector originInDialogSpace, sizeInDialogSpace;
516 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
517 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
519 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
520 btn.Container_size_x = sizeInDialogSpace_x * theSize;
521 btn.setText(btn, theTitle);
522 btn.onClick = theFunc;
523 btn.onClickEntity = me;
526 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
528 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
530 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
531 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
532 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
534 me.columnIconsOrigin = 0;
535 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
536 me.columnPingSize = me.realFontSize_x * 3;
537 me.columnMapSize = me.realFontSize_x * 10;
538 me.columnTypeSize = me.realFontSize_x * 4;
539 me.columnPlayersSize = me.realFontSize_x * 5;
540 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
541 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
542 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
543 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
544 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
545 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
547 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
548 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
549 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
550 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
551 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
554 f = me.currentSortField;
557 me.currentSortField = -1;
558 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
561 void ServerList_Connect_Click(entity btn, entity me)
563 if(me.ipAddressBox.text == "")
564 localcmd("connect ", me.selectedServer, "\n");
566 localcmd("connect ", me.ipAddressBox.text, "\n");
568 void ServerList_Favorite_Click(entity btn, entity me)
571 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
574 ToggleFavorite(me.ipAddressBox.text);
575 me.ipAddressBoxFocused = -1;
578 void ServerList_Info_Click(entity btn, entity me)
580 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
581 DialogOpenButton_Click(me, main.serverInfoDialog);
583 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
585 if(i == me.lastClickedServer)
586 if(time < me.lastClickedTime + 0.3)
589 ServerList_Connect_Click(NULL, me);
591 me.lastClickedServer = i;
592 me.lastClickedTime = time;
594 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
596 // layout: Ping, Server name, Map name, NP, TP, MP
604 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
606 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
607 theAlpha = SKINALPHA_SERVERLIST_FULL;
608 else if(strstrofs(gethostcachestring(SLIST_FIELD_QCSTATUS, i), ":S0:", 0) >= 0)
609 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
610 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
611 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
615 p = gethostcachenumber(SLIST_FIELD_PING, i);
618 #define PING_HIGH 500
620 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
621 else if(p < PING_MED)
622 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
623 else if(p < PING_HIGH)
625 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
626 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
631 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
634 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
636 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
637 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
640 s = gethostcachestring(SLIST_FIELD_CNAME, i);
643 if(substring(s, 0, 1) == "[")
648 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
654 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
655 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
657 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
658 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
663 if(cvar("crypto_aeslevel") >= 2)
668 if(cvar("crypto_aeslevel") >= 1)
678 // 2: AES recommended but not available
679 // 3: AES possible and will be used
680 // 4: AES recommended and will be used
683 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
686 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
687 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
690 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
691 iconPos_y = (1 - iconSize_y) * 0.5;
693 if not(me.seenIPv4 && me.seenIPv6)
695 iconPos_x += iconSize_x * 0.5;
697 else if(me.seenIPv4 && me.seenIPv6)
700 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
702 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
703 iconPos_x += iconSize_x;
706 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
707 iconPos_x += iconSize_x;
709 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
710 iconPos_x += iconSize_x;
714 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
715 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
716 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
717 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
718 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
719 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
720 p = strstrofs(s, ":", 0);
722 s = substring(s, 0, p);
725 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
726 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
727 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
728 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
731 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
736 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
737 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
739 if(scan == K_ENTER || scan == K_KP_ENTER)
741 ServerList_Connect_Click(NULL, me);
744 else if(scan == K_MOUSE2 || scan == K_SPACE)
748 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
749 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
752 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
757 ToggleFavorite(me.selectedServer);
758 me.ipAddressBoxFocused = -1;
761 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
763 else if(!me.controlledTextbox)
766 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);