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();
61 void ServerList_Connect_Click(entity btn, entity me);
62 void ServerList_ShowEmpty_Click(entity box, entity me);
63 void ServerList_ShowFull_Click(entity box, entity me);
64 void ServerList_Filter_Change(entity box, entity me);
65 void ServerList_Favorite_Click(entity btn, entity me);
66 void ServerList_Info_Click(entity btn, entity me);
67 void ServerList_Update_favoriteButton(entity btn, entity me);
69 #ifndef IMPLEMENTATION
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;
90 void ServerList_UpdateFieldIDs()
92 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
93 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
94 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
95 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
96 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
97 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
98 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
99 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
100 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
101 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
102 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
103 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
104 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
105 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
106 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
109 float IsFavorite(string srv)
115 srv = netaddress_resolve(srv, 26000);
118 p = crypto_getidfp(srv);
119 n = tokenize_console(cvar_string("net_slist_favorites"));
120 for(i = 0; i < n; ++i)
122 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
130 if(srv == netaddress_resolve(argv(i), 26000))
137 void ToggleFavorite(string srv)
139 string s, s0, s1, s2, srv_resolved, p;
141 srv_resolved = netaddress_resolve(srv, 26000);
142 p = crypto_getidfp(srv_resolved);
143 s = cvar_string("net_slist_favorites");
144 n = tokenize_console(s);
146 for(i = 0; i < n; ++i)
148 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
156 if(srv_resolved != netaddress_resolve(argv(i), 26000))
161 s0 = substring(s, 0, argv_end_index(i - 1));
163 s2 = substring(s, argv_start_index(i + 1), -1);
164 if(s0 != "" && s2 != "")
166 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
167 s = cvar_string("net_slist_favorites");
168 n = tokenize_console(s);
179 cvar_set("net_slist_favorites", strcat(s, s1, p));
181 cvar_set("net_slist_favorites", strcat(s, s1, srv));
187 void ServerList_Update_favoriteButton(entity btn, entity me)
189 if(IsFavorite(me.ipAddressBox.text))
190 me.favoriteButton.setText(me.favoriteButton, _("Remove"));
192 me.favoriteButton.setText(me.favoriteButton, _("Bookmark"));
195 entity makeXonoticServerList()
198 me = spawnXonoticServerList();
199 me.configureXonoticServerList(me);
202 void XonoticServerList_configureXonoticServerList(entity me)
204 me.configureXonoticListBox(me);
206 ServerList_UpdateFieldIDs();
210 void XonoticServerList_setSelected(entity me, float i)
213 save = me.selectedItem;
214 SUPER(XonoticServerList).setSelected(me, i);
216 if(me.selectedItem == save)
221 //if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
222 // return; // sorry, it would be wrong
224 if(me.selectedServer)
225 strunzone(me.selectedServer);
226 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
228 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
229 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
230 me.ipAddressBoxFocused = -1;
232 void XonoticServerList_refreshServerList(entity me, float mode)
234 // 0: just reparametrize
235 // 1: also ask for new servers
237 //print("refresh of type ", ftos(mode), "\n");
238 /* if(mode == 2) // borken
241 localcmd("net_slist\n");
242 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
246 float m, o, i, n; // moin moin
247 string s, typestr, modstr;
250 m = strstrofs(s, ":", 0);
253 typestr = substring(s, 0, m);
254 s = substring(s, m + 1, strlen(s) - m - 1);
255 while(substring(s, 0, 1) == " ")
256 s = substring(s, 1, strlen(s) - 1);
261 modstr = cvar_string("menu_slist_modfilter");
263 m = SLIST_MASK_AND - 1;
264 resethostcachemasks();
266 // ping: reject negative ping (no idea why this happens in the first place, engine bug)
267 sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
270 if(!me.filterShowFull)
272 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
273 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
277 if(!me.filterShowEmpty)
278 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
280 // gametype filtering
282 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
287 if(substring(modstr, 0, 1) == "!")
288 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
290 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
294 n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
295 for(i = 0; i < n; ++i)
297 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
299 m = SLIST_MASK_OR - 1;
302 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
303 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
304 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
305 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
307 o = 2; // favorites first
308 if(me.currentSortOrder < 0)
309 o |= 1; // descending
310 sethostcachesort(me.currentSortField, o);
316 void XonoticServerList_focusEnter(entity me)
318 if(time < me.nextRefreshTime)
320 //print("sorry, no refresh yet\n");
323 me.nextRefreshTime = time + 10;
324 me.refreshServerList(me, 1);
326 float category_drawn;
327 void XonoticServerList_draw(entity me)
329 float i, found, owned;
331 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
335 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
338 if(me.currentSortField == -1)
340 me.setSortOrder(me, SLIST_FIELD_PING, +1);
341 me.refreshServerList(me, 2);
343 else if(me.needsRefresh == 1)
345 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
347 else if(me.needsRefresh == 2)
350 me.refreshServerList(me, 0);
353 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
355 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) + 1;
357 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
358 me.infoButton.disabled = ((me.nItems == 0) || !owned);
359 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
362 if(me.selectedServer)
364 for(i = 0; i < me.nItems; ++i)
365 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
367 if(i != me.selectedItem)
369 me.lastClickedServer = -1;
379 if(me.selectedItem >= me.nItems)
380 me.selectedItem = me.nItems - 1;
381 if(me.selectedServer)
382 strunzone(me.selectedServer);
383 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
388 if(me.selectedServer != me.ipAddressBox.text)
390 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
391 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
392 me.ipAddressBoxFocused = -1;
396 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
398 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
399 ServerList_Update_favoriteButton(NULL, me);
400 me.ipAddressBoxFocused = me.ipAddressBox.focused;
404 SUPER(XonoticServerList).draw(me);
406 void ServerList_PingSort_Click(entity btn, entity me)
408 me.setSortOrder(me, SLIST_FIELD_PING, +1);
410 void ServerList_NameSort_Click(entity btn, entity me)
412 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
414 void ServerList_MapSort_Click(entity btn, entity me)
416 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
418 void ServerList_PlayerSort_Click(entity btn, entity me)
420 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
422 void ServerList_TypeSort_Click(entity btn, entity me)
427 m = strstrofs(s, ":", 0);
430 s = substring(s, 0, m);
431 while(substring(s, m+1, 1) == " ") // skip spaces
437 for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
439 t = MapInfo_Type_ToString(i);
441 if(t == "") // it repeats (default case)
444 // choose the first one
445 s = MapInfo_Type_ToString(1);
450 // the type was found
451 // choose the next one
452 s = MapInfo_Type_ToString(i * 2);
454 s = MapInfo_Type_ToString(1);
461 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
463 me.controlledTextbox.setText(me.controlledTextbox, s);
464 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
465 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
466 //ServerList_Filter_Change(me.controlledTextbox, me);
468 void ServerList_Filter_Change(entity box, entity me)
471 strunzone(me.filterString);
473 me.filterString = strzone(box.text);
475 me.filterString = string_null;
476 me.refreshServerList(me, 0);
478 me.ipAddressBox.setText(me.ipAddressBox, "");
479 me.ipAddressBox.cursorPos = 0;
480 me.ipAddressBoxFocused = -1;
482 void ServerList_ShowEmpty_Click(entity box, entity me)
484 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
485 me.refreshServerList(me, 0);
487 me.ipAddressBox.setText(me.ipAddressBox, "");
488 me.ipAddressBox.cursorPos = 0;
489 me.ipAddressBoxFocused = -1;
491 void ServerList_ShowFull_Click(entity box, entity me)
493 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
494 me.refreshServerList(me, 0);
496 me.ipAddressBox.setText(me.ipAddressBox, "");
497 me.ipAddressBox.cursorPos = 0;
498 me.ipAddressBoxFocused = -1;
500 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
502 if(me.currentSortField == fld)
503 direction = -me.currentSortOrder;
504 me.currentSortOrder = direction;
505 me.currentSortField = fld;
506 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
507 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
508 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
509 me.sortButton4.forcePressed = 0;
510 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
512 if(me.selectedServer)
513 strunzone(me.selectedServer);
514 me.selectedServer = string_null;
515 me.refreshServerList(me, 0);
517 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
519 vector originInLBSpace, sizeInLBSpace;
520 originInLBSpace = eY * (-me.itemHeight);
521 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
523 vector originInDialogSpace, sizeInDialogSpace;
524 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
525 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
527 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
528 btn.Container_size_x = sizeInDialogSpace_x * theSize;
529 btn.setText(btn, theTitle);
530 btn.onClick = theFunc;
531 btn.onClickEntity = me;
534 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
536 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
538 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
539 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
540 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
542 me.columnIconsOrigin = 0;
543 me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
544 me.columnPingSize = me.realFontSize_x * 3;
545 me.columnMapSize = me.realFontSize_x * 10;
546 me.columnTypeSize = me.realFontSize_x * 4;
547 me.columnPlayersSize = me.realFontSize_x * 5;
548 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
549 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
550 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
551 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
552 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
553 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
555 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
556 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
557 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
558 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
559 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
562 f = me.currentSortField;
565 me.currentSortField = -1;
566 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
569 void ServerList_Connect_Click(entity btn, entity me)
571 if(me.ipAddressBox.text == "")
572 localcmd("connect ", me.selectedServer, "\n");
574 localcmd("connect ", me.ipAddressBox.text, "\n");
576 void ServerList_Favorite_Click(entity btn, entity me)
579 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
582 ToggleFavorite(me.ipAddressBox.text);
583 me.ipAddressBoxFocused = -1;
586 void ServerList_Info_Click(entity btn, entity me)
588 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
589 DialogOpenButton_Click(me, main.serverInfoDialog);
591 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
593 if(i == me.lastClickedServer)
594 if(time < me.lastClickedTime + 0.3)
597 ServerList_Connect_Click(NULL, me);
599 me.lastClickedServer = i;
600 me.lastClickedTime = time;
602 float category_drawn;
603 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
605 // layout: Ping, Server name, Map name, NP, TP, MP
610 float m, pure, freeslots, j, sflags;
611 string s, typestr, versionstr, k, v, modname;
618 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
622 draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth("category", 0, me.realFontSize)) * 0.5) * eX, "category", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
623 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
624 category_drawn = TRUE;
628 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
630 s = gethostcachestring(SLIST_FIELD_QCSTATUS, cache);
631 m = tokenizebyseparator(s, ":");
636 versionstr = argv(1);
642 for(j = 2; j < m; ++j)
646 k = substring(argv(j), 0, 1);
647 v = substring(argv(j), 1, -1);
658 #ifdef COMPAT_NO_MOD_IS_XONOTIC
664 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
665 s = gethostcachestring(SLIST_FIELD_MOD, cache);
667 if(modname == "Xonotic")
671 // list the mods here on which the pure server check actually works
672 if(modname != "Xonotic")
673 if(modname != "MinstaGib")
676 if(modname != "NewToys")
679 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, cache) <= 0)
680 theAlpha = SKINALPHA_SERVERLIST_FULL;
681 else if(freeslots == 0)
682 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
683 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache))
684 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
688 p = gethostcachenumber(SLIST_FIELD_PING, cache);
691 #define PING_HIGH 500
693 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
694 else if(p < PING_MED)
695 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
696 else if(p < PING_HIGH)
698 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
699 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
704 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
707 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, cache))
709 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
710 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
713 s = gethostcachestring(SLIST_FIELD_CNAME, cache);
716 if(substring(s, 0, 1) == "[")
721 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
727 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
728 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
730 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
731 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
736 if(cvar("crypto_aeslevel") >= 2)
741 if(cvar("crypto_aeslevel") >= 1)
751 // 2: AES recommended but not available
752 // 3: AES possible and will be used
753 // 4: AES recommended and will be used
757 vector iconSize = '0 0 0';
758 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
759 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
761 vector iconPos = '0 0 0';
762 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
763 iconPos_y = (1 - iconSize_y) * 0.5;
767 if not(me.seenIPv4 && me.seenIPv6)
769 iconPos_x += iconSize_x * 0.5;
771 else if(me.seenIPv4 && me.seenIPv6)
775 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
777 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
779 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
780 iconPos_x += iconSize_x;
785 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
786 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
788 iconPos_x += iconSize_x;
790 if(modname == "Xonotic")
794 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
795 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
800 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
801 if(draw_PictureSize(n) == '0 0 0')
802 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
804 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
806 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
808 iconPos_x += iconSize_x;
810 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
812 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
813 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
815 iconPos_x += iconSize_x;
819 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
820 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, cache), me.columnNameSize, 0, me.realFontSize);
821 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
822 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, cache), me.columnMapSize, 0, me.realFontSize);
823 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
824 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
825 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
826 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, cache)));
827 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
830 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
835 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
836 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
838 if(scan == K_ENTER || scan == K_KP_ENTER)
840 ServerList_Connect_Click(NULL, me);
843 else if(scan == K_MOUSE2 || scan == K_SPACE)
847 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
848 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
853 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
858 ToggleFavorite(me.selectedServer);
859 me.ipAddressBoxFocused = -1;
864 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
866 else if(!me.controlledTextbox)
869 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);