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_CATEGORY;
85 float SLIST_FIELD_ISFAVORITE;
86 float SLSF_DESCENDING = 1;
87 float SLSF_FAVORITES = 2;
88 float SLSF_CATEGORIES = 3;
94 void ServerList_UpdateFieldIDs()
96 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
97 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
98 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
99 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
100 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
101 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
102 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
103 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
104 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
105 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
106 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
107 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
108 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
109 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
110 SLIST_FIELD_CATEGORY = gethostcacheindexforkey( "category" );
111 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
114 float IsFavorite(string srv)
120 srv = netaddress_resolve(srv, 26000);
123 p = crypto_getidfp(srv);
124 n = tokenize_console(cvar_string("net_slist_favorites"));
125 for(i = 0; i < n; ++i)
127 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
135 if(srv == netaddress_resolve(argv(i), 26000))
142 void ToggleFavorite(string srv)
144 string s, s0, s1, s2, srv_resolved, p;
146 srv_resolved = netaddress_resolve(srv, 26000);
147 p = crypto_getidfp(srv_resolved);
148 s = cvar_string("net_slist_favorites");
149 n = tokenize_console(s);
151 for(i = 0; i < n; ++i)
153 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
161 if(srv_resolved != netaddress_resolve(argv(i), 26000))
166 s0 = substring(s, 0, argv_end_index(i - 1));
168 s2 = substring(s, argv_start_index(i + 1), -1);
169 if(s0 != "" && s2 != "")
171 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
172 s = cvar_string("net_slist_favorites");
173 n = tokenize_console(s);
184 cvar_set("net_slist_favorites", strcat(s, s1, p));
186 cvar_set("net_slist_favorites", strcat(s, s1, srv));
192 void ServerList_Update_favoriteButton(entity btn, entity me)
194 if(IsFavorite(me.ipAddressBox.text))
195 me.favoriteButton.setText(me.favoriteButton, _("Remove"));
197 me.favoriteButton.setText(me.favoriteButton, _("Bookmark"));
200 entity makeXonoticServerList()
203 me = spawnXonoticServerList();
204 me.configureXonoticServerList(me);
207 void XonoticServerList_configureXonoticServerList(entity me)
209 me.configureXonoticListBox(me);
211 ServerList_UpdateFieldIDs();
215 void XonoticServerList_setSelected(entity me, float i)
218 save = me.selectedItem;
219 SUPER(XonoticServerList).setSelected(me, i);
221 if(me.selectedItem == save)
226 //if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
227 // return; // sorry, it would be wrong
229 if(me.selectedServer)
230 strunzone(me.selectedServer);
231 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
233 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
234 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
235 me.ipAddressBoxFocused = -1;
237 void XonoticServerList_refreshServerList(entity me, float mode)
239 // 0: just reparametrize
240 // 1: also ask for new servers
242 //print("refresh of type ", ftos(mode), "\n");
243 /* if(mode == 2) // borken
246 localcmd("net_slist\n");
247 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
253 string s, typestr, modstr;
256 m = strstrofs(s, ":", 0);
259 typestr = substring(s, 0, m);
260 s = substring(s, m + 1, strlen(s) - m - 1);
261 while(substring(s, 0, 1) == " ")
262 s = substring(s, 1, strlen(s) - 1);
267 modstr = cvar_string("menu_slist_modfilter");
269 m = SLIST_MASK_AND - 1;
270 resethostcachemasks();
272 // ping: reject negative ping (no idea why this happens in the first place, engine bug)
273 sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
276 if(!me.filterShowFull)
278 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
279 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
283 if(!me.filterShowEmpty)
284 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
286 // gametype filtering
288 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
293 if(substring(modstr, 0, 1) == "!")
294 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
296 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
300 n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
301 for(i = 0; i < n; ++i)
303 sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
305 m = SLIST_MASK_OR - 1;
308 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
309 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
310 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
311 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
315 listflags |= SLSF_FAVORITES;
316 listflags |= SLSF_CATEGORIES;
317 if(me.currentSortOrder < 0) { listflags |= SLSF_DESCENDING; }
318 sethostcachesort(me.currentSortField, listflags);
325 void XonoticServerList_focusEnter(entity me)
327 if(time < me.nextRefreshTime)
329 //print("sorry, no refresh yet\n");
332 me.nextRefreshTime = time + 10;
333 me.refreshServerList(me, 1);
335 float category_drawn;
336 void XonoticServerList_draw(entity me)
338 float i, found, owned;
340 if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
344 _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
347 if(me.currentSortField == -1)
349 me.setSortOrder(me, SLIST_FIELD_PING, +1);
350 me.refreshServerList(me, 2);
352 else if(me.needsRefresh == 1)
354 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
356 else if(me.needsRefresh == 2)
359 me.refreshServerList(me, 0);
362 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
364 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) + 1;
366 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
367 me.infoButton.disabled = ((me.nItems == 0) || !owned);
368 me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
371 if(me.selectedServer)
373 for(i = 0; i < me.nItems; ++i)
374 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
376 if(i != me.selectedItem)
378 me.lastClickedServer = -1;
388 if(me.selectedItem >= me.nItems)
389 me.selectedItem = me.nItems - 1;
390 if(me.selectedServer)
391 strunzone(me.selectedServer);
392 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
397 if(me.selectedServer != me.ipAddressBox.text)
399 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
400 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
401 me.ipAddressBoxFocused = -1;
405 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
407 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
408 ServerList_Update_favoriteButton(NULL, me);
409 me.ipAddressBoxFocused = me.ipAddressBox.focused;
413 SUPER(XonoticServerList).draw(me);
415 void ServerList_PingSort_Click(entity btn, entity me)
417 me.setSortOrder(me, SLIST_FIELD_PING, +1);
419 void ServerList_NameSort_Click(entity btn, entity me)
421 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
423 void ServerList_MapSort_Click(entity btn, entity me)
425 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
427 void ServerList_PlayerSort_Click(entity btn, entity me)
429 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
431 void ServerList_TypeSort_Click(entity btn, entity me)
436 m = strstrofs(s, ":", 0);
439 s = substring(s, 0, m);
440 while(substring(s, m+1, 1) == " ") // skip spaces
446 for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
448 t = MapInfo_Type_ToString(i);
450 if(t == "") // it repeats (default case)
453 // choose the first one
454 s = MapInfo_Type_ToString(1);
459 // the type was found
460 // choose the next one
461 s = MapInfo_Type_ToString(i * 2);
463 s = MapInfo_Type_ToString(1);
470 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
472 me.controlledTextbox.setText(me.controlledTextbox, s);
473 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
474 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
475 //ServerList_Filter_Change(me.controlledTextbox, me);
477 void ServerList_Filter_Change(entity box, entity me)
480 strunzone(me.filterString);
482 me.filterString = strzone(box.text);
484 me.filterString = string_null;
485 me.refreshServerList(me, 0);
487 me.ipAddressBox.setText(me.ipAddressBox, "");
488 me.ipAddressBox.cursorPos = 0;
489 me.ipAddressBoxFocused = -1;
491 void ServerList_ShowEmpty_Click(entity box, entity me)
493 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
494 me.refreshServerList(me, 0);
496 me.ipAddressBox.setText(me.ipAddressBox, "");
497 me.ipAddressBox.cursorPos = 0;
498 me.ipAddressBoxFocused = -1;
500 void ServerList_ShowFull_Click(entity box, entity me)
502 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
503 me.refreshServerList(me, 0);
505 me.ipAddressBox.setText(me.ipAddressBox, "");
506 me.ipAddressBox.cursorPos = 0;
507 me.ipAddressBoxFocused = -1;
509 void XonoticServerList_setSortOrder(entity me, float fld, float direction)
511 if(me.currentSortField == fld)
512 direction = -me.currentSortOrder;
513 me.currentSortOrder = direction;
514 me.currentSortField = fld;
515 me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
516 me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
517 me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
518 me.sortButton4.forcePressed = 0;
519 me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
521 if(me.selectedServer)
522 strunzone(me.selectedServer);
523 me.selectedServer = string_null;
524 me.refreshServerList(me, 0);
526 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
528 vector originInLBSpace, sizeInLBSpace;
529 originInLBSpace = eY * (-me.itemHeight);
530 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
532 vector originInDialogSpace, sizeInDialogSpace;
533 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
534 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
536 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
537 btn.Container_size_x = sizeInDialogSpace_x * theSize;
538 btn.setText(btn, theTitle);
539 btn.onClick = theFunc;
540 btn.onClickEntity = me;
543 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
545 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
547 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
548 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
549 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
551 me.columnIconsOrigin = 0;
552 me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
553 me.columnPingSize = me.realFontSize_x * 3;
554 me.columnMapSize = me.realFontSize_x * 10;
555 me.columnTypeSize = me.realFontSize_x * 4;
556 me.columnPlayersSize = me.realFontSize_x * 5;
557 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
558 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
559 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
560 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
561 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
562 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
564 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, _("Ping"), ServerList_PingSort_Click);
565 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, _("Host name"), ServerList_NameSort_Click);
566 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, _("Map"), ServerList_MapSort_Click);
567 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
568 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
571 f = me.currentSortField;
574 me.currentSortField = -1;
575 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
578 void ServerList_Connect_Click(entity btn, entity me)
580 if(me.ipAddressBox.text == "")
581 localcmd("connect ", me.selectedServer, "\n");
583 localcmd("connect ", me.ipAddressBox.text, "\n");
585 void ServerList_Favorite_Click(entity btn, entity me)
588 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
591 ToggleFavorite(me.ipAddressBox.text);
592 me.ipAddressBoxFocused = -1;
595 void ServerList_Info_Click(entity btn, entity me)
597 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
598 DialogOpenButton_Click(me, main.serverInfoDialog);
600 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
602 if(i == me.lastClickedServer)
603 if(time < me.lastClickedTime + 0.3)
606 ServerList_Connect_Click(NULL, me);
608 me.lastClickedServer = i;
609 me.lastClickedTime = time;
611 float category_drawn;
612 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
614 // layout: Ping, Server name, Map name, NP, TP, MP
619 float m, pure, freeslots, j, sflags;
620 string s, typestr, versionstr, k, v, modname;
627 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
631 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);
632 print(sprintf("time: %f, category_drawn: %d, i: %d, cache: %d, nitems: %d\n", time, category_drawn, i, cache, me.nItems));
633 category_drawn = TRUE;
637 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
639 s = gethostcachestring(SLIST_FIELD_QCSTATUS, cache);
640 m = tokenizebyseparator(s, ":");
645 versionstr = argv(1);
651 for(j = 2; j < m; ++j)
655 k = substring(argv(j), 0, 1);
656 v = substring(argv(j), 1, -1);
667 #ifdef COMPAT_NO_MOD_IS_XONOTIC
673 SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
674 s = gethostcachestring(SLIST_FIELD_MOD, cache);
676 if(modname == "Xonotic")
680 // list the mods here on which the pure server check actually works
681 if(modname != "Xonotic")
682 if(modname != "MinstaGib")
685 if(modname != "NewToys")
688 if(gethostcachenumber(SLIST_FIELD_FREESLOTS, cache) <= 0)
689 theAlpha = SKINALPHA_SERVERLIST_FULL;
690 else if(freeslots == 0)
691 theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
692 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache))
693 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
697 p = gethostcachenumber(SLIST_FIELD_PING, cache);
700 #define PING_HIGH 500
702 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
703 else if(p < PING_MED)
704 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
705 else if(p < PING_HIGH)
707 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
708 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
713 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
716 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, cache))
718 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
719 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
722 s = gethostcachestring(SLIST_FIELD_CNAME, cache);
725 if(substring(s, 0, 1) == "[")
730 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
736 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
737 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
739 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
740 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
745 if(cvar("crypto_aeslevel") >= 2)
750 if(cvar("crypto_aeslevel") >= 1)
760 // 2: AES recommended but not available
761 // 3: AES possible and will be used
762 // 4: AES recommended and will be used
766 vector iconSize = '0 0 0';
767 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
768 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
770 vector iconPos = '0 0 0';
771 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
772 iconPos_y = (1 - iconSize_y) * 0.5;
776 if not(me.seenIPv4 && me.seenIPv6)
778 iconPos_x += iconSize_x * 0.5;
780 else if(me.seenIPv4 && me.seenIPv6)
784 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
786 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
788 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
789 iconPos_x += iconSize_x;
794 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
795 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
797 iconPos_x += iconSize_x;
799 if(modname == "Xonotic")
803 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
804 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
809 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
810 if(draw_PictureSize(n) == '0 0 0')
811 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
813 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
815 draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
817 iconPos_x += iconSize_x;
819 if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
821 draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
822 draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
824 iconPos_x += iconSize_x;
828 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
829 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, cache), me.columnNameSize, 0, me.realFontSize);
830 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
831 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, cache), me.columnMapSize, 0, me.realFontSize);
832 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
833 s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
834 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
835 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, cache)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, cache)));
836 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
839 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
844 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
845 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
847 if(scan == K_ENTER || scan == K_KP_ENTER)
849 ServerList_Connect_Click(NULL, me);
852 else if(scan == K_MOUSE2 || scan == K_SPACE)
856 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
857 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
862 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
867 ToggleFavorite(me.selectedServer);
868 me.ipAddressBoxFocused = -1;
873 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
875 else if(!me.controlledTextbox)
878 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);