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);
69 float SLIST_FIELD_CNAME;
70 float SLIST_FIELD_PING;
71 float SLIST_FIELD_GAME;
72 float SLIST_FIELD_MOD;
73 float SLIST_FIELD_MAP;
74 float SLIST_FIELD_NAME;
75 float SLIST_FIELD_MAXPLAYERS;
76 float SLIST_FIELD_NUMPLAYERS;
77 float SLIST_FIELD_NUMHUMANS;
78 float SLIST_FIELD_NUMBOTS;
79 float SLIST_FIELD_PROTOCOL;
80 float SLIST_FIELD_FREESLOTS;
81 float SLIST_FIELD_PLAYERS;
82 float SLIST_FIELD_QCSTATUS;
83 float SLIST_FIELD_ISFAVORITE;
84 void ServerList_UpdateFieldIDs()
86 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
87 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
88 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
89 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
90 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
91 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
92 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
93 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
94 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
95 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
96 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
97 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
98 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
99 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
100 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
103 float IsFavorite(string srv)
109 srv = netaddress_resolve(srv, 26000);
110 p = crypto_getidfp(srv);
111 n = tokenize_console(cvar_string("net_slist_favorites"));
112 for(i = 0; i < n; ++i)
114 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
122 if(srv == netaddress_resolve(argv(i), 26000))
129 void ToggleFavorite(string srv)
131 string s, s0, s1, s2, srv_resolved, p;
133 srv_resolved = netaddress_resolve(srv, 26000);
134 p = crypto_getidfp(srv_resolved);
135 s = cvar_string("net_slist_favorites");
136 n = tokenize_console(s);
138 for(i = 0; i < n; ++i)
140 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
148 if(srv_resolved != netaddress_resolve(argv(i), 26000))
153 s0 = substring(s, 0, argv_end_index(i - 1));
155 s2 = substring(s, argv_start_index(i + 1), -1);
156 if(s0 != "" && s2 != "")
158 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
159 s = cvar_string("net_slist_favorites");
160 n = tokenize_console(s);
171 cvar_set("net_slist_favorites", strcat(s, s1, p));
173 cvar_set("net_slist_favorites", strcat(s, s1, srv));
179 entity makeXonoticServerList()
182 me = spawnXonoticServerList();
183 me.configureXonoticServerList(me);
186 void XonoticServerList_configureXonoticServerList(entity me)
188 me.configureXonoticListBox(me);
190 ServerList_UpdateFieldIDs();
194 void XonoticServerList_setSelected(entity me, float i)
197 save = me.selectedItem;
198 SUPER(XonoticServerList).setSelected(me, i);
200 if(me.selectedItem == save)
205 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
206 return; // sorry, it would be wrong
208 if(me.selectedServer)
209 strunzone(me.selectedServer);
210 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
212 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
213 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
214 me.ipAddressBoxFocused = -1;
216 void XonoticServerList_refreshServerList(entity me, float mode)
218 // 0: just reparametrize
219 // 1: also ask for new servers
221 //print("refresh of type ", ftos(mode), "\n");
222 /* if(mode == 2) // borken
225 localcmd("net_slist\n");
226 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
231 string s, typestr, modstr;
234 m = strstrofs(s, ":", 0);
237 typestr = substring(s, 0, m);
238 s = substring(s, m + 1, strlen(s) - m - 1);
239 while(substring(s, 0, 1) == " ")
240 s = substring(s, 1, strlen(s) - 1);
245 modstr = cvar_string("menu_slist_modfilter");
247 m = SLIST_MASK_AND - 1;
248 resethostcachemasks();
249 if(!me.filterShowFull)
250 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
251 if(!me.filterShowEmpty)
252 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
254 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
257 if(substring(modstr, 0, 1) == "!")
258 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
260 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
262 m = SLIST_MASK_OR - 1;
265 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
266 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
267 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
268 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
270 o = 2; // favorites first
271 if(me.currentSortOrder < 0)
272 o |= 1; // descending
273 sethostcachesort(me.currentSortField, o);
279 void XonoticServerList_focusEnter(entity me)
281 if(time < me.nextRefreshTime)
283 //print("sorry, no refresh yet\n");
286 me.nextRefreshTime = time + 10;
287 me.refreshServerList(me, 1);
289 void XonoticServerList_draw(entity me)
291 float i, found, owned;
293 if(me.currentSortField == -1)
295 me.setSortOrder(me, SLIST_FIELD_PING, +1);
296 me.refreshServerList(me, 2);
298 else if(me.needsRefresh == 1)
300 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
302 else if(me.needsRefresh == 2)
305 me.refreshServerList(me, 0);
308 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
310 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
312 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
313 me.infoButton.disabled = ((me.nItems == 0) || !owned);
316 if(me.selectedServer)
318 for(i = 0; i < me.nItems; ++i)
319 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
321 if(i != me.selectedItem)
323 me.lastClickedServer = -1;
333 if(me.selectedItem >= me.nItems)
334 me.selectedItem = me.nItems - 1;
335 if(me.selectedServer)
336 strunzone(me.selectedServer);
337 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
342 if(me.selectedServer != me.ipAddressBox.text)
344 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
345 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
346 me.ipAddressBoxFocused = -1;
350 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
352 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
354 if(IsFavorite(me.ipAddressBox.text))
355 me.favoriteButton.setText(me.favoriteButton, "Remove");
357 me.favoriteButton.setText(me.favoriteButton, "Bookmark");
359 me.ipAddressBoxFocused = me.ipAddressBox.focused;
362 SUPER(XonoticServerList).draw(me);
364 void ServerList_PingSort_Click(entity btn, entity me)
366 me.setSortOrder(me, SLIST_FIELD_PING, +1);
368 void ServerList_NameSort_Click(entity btn, entity me)
370 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
372 void ServerList_MapSort_Click(entity btn, entity me)
374 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
376 void ServerList_PlayerSort_Click(entity btn, entity me)
378 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
380 void ServerList_TypeSort_Click(entity btn, entity me)
385 m = strstrofs(s, ":", 0);
388 s = substring(s, 0, m);
389 while(substring(s, m+1, 1) == " ") // skip spaces
395 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
397 t = GametypeNameFromType(i);
399 if(t == GametypeNameFromType(0)) // it repeats (default case)
402 // choose the first one
406 if(s == GametypeNameFromType(i))
408 // the type was found
409 // choose the next one
410 s = GametypeNameFromType(i + 1);
411 if(s == GametypeNameFromType(0))
419 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
421 me.controlledTextbox.setText(me.controlledTextbox, s);
422 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
423 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
424 //ServerList_Filter_Change(me.controlledTextbox, me);
426 void ServerList_Filter_Change(entity box, entity me)
429 strunzone(me.filterString);
431 me.filterString = strzone(box.text);
433 me.filterString = string_null;
434 me.refreshServerList(me, 0);
436 me.ipAddressBox.setText(me.ipAddressBox, "");
437 me.ipAddressBox.cursorPos = 0;
438 me.ipAddressBoxFocused = -1;
440 void ServerList_ShowEmpty_Click(entity box, entity me)
442 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
443 me.refreshServerList(me, 0);
445 me.ipAddressBox.setText(me.ipAddressBox, "");
446 me.ipAddressBox.cursorPos = 0;
447 me.ipAddressBoxFocused = -1;
449 void ServerList_ShowFull_Click(entity box, entity me)
451 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
452 me.refreshServerList(me, 0);
454 me.ipAddressBox.setText(me.ipAddressBox, "");
455 me.ipAddressBox.cursorPos = 0;
456 me.ipAddressBoxFocused = -1;
458 void XonoticServerList_setSortOrder(entity me, float field, float direction)
460 if(me.currentSortField == field)
461 direction = -me.currentSortOrder;
462 me.currentSortOrder = direction;
463 me.currentSortField = field;
464 me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
465 me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
466 me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
467 me.sortButton4.forcePressed = 0;
468 me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
470 if(me.selectedServer)
471 strunzone(me.selectedServer);
472 me.selectedServer = string_null;
473 me.refreshServerList(me, 0);
475 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
477 vector originInLBSpace, sizeInLBSpace;
478 originInLBSpace = eY * (-me.itemHeight);
479 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
481 vector originInDialogSpace, sizeInDialogSpace;
482 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
483 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
485 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
486 btn.Container_size_x = sizeInDialogSpace_x * theSize;
487 btn.setText(btn, theTitle);
488 btn.onClick = theFunc;
489 btn.onClickEntity = me;
492 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
494 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
496 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
497 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
498 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
500 me.columnIconsOrigin = 0;
501 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
502 me.columnPingSize = me.realFontSize_x * 3;
503 me.columnMapSize = me.realFontSize_x * 10;
504 me.columnTypeSize = me.realFontSize_x * 4;
505 me.columnPlayersSize = me.realFontSize_x * 5;
506 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
507 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
508 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
509 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
510 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
511 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
513 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
514 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
515 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
516 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);
517 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
520 f = me.currentSortField;
523 me.currentSortField = -1;
524 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
527 void ServerList_Connect_Click(entity btn, entity me)
529 if(me.ipAddressBox.text == "")
530 localcmd("connect ", me.selectedServer, "\n");
532 localcmd("connect ", me.ipAddressBox.text, "\n");
534 void ServerList_Favorite_Click(entity btn, entity me)
537 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
540 ToggleFavorite(me.ipAddressBox.text);
541 me.ipAddressBoxFocused = -1;
544 void ServerList_Info_Click(entity btn, entity me)
546 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
547 DialogOpenButton_Click(me, main.serverInfoDialog);
549 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
551 if(i == me.lastClickedServer)
552 if(time < me.lastClickedTime + 0.3)
555 ServerList_Connect_Click(NULL, me);
557 me.lastClickedServer = i;
558 me.lastClickedTime = time;
560 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
562 // layout: Ping, Server name, Map name, NP, TP, MP
570 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
572 if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
573 theAlpha = SKINALPHA_SERVERLIST_FULL;
574 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
575 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
579 p = gethostcachenumber(SLIST_FIELD_PING, i);
582 #define PING_HIGH 500
584 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
585 else if(p < PING_MED)
586 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
587 else if(p < PING_HIGH)
589 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
590 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
595 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
598 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
600 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
601 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
604 s = gethostcachestring(SLIST_FIELD_CNAME, i);
607 if(substring(s, 0, 1) == "[")
612 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
618 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
619 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
621 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
622 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
627 if(cvar("crypto_aeslevel") >= 2)
632 if(cvar("crypto_aeslevel") >= 1)
642 // 2: AES recommended but not available
643 // 3: AES possible and will be used
644 // 4: AES recommended and will be used
647 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
650 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
651 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
654 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
655 iconPos_y = (1 - iconSize_y) * 0.5;
657 if not(me.seenIPv4 && me.seenIPv6)
659 iconPos_x += iconSize_x * 0.5;
661 else if(me.seenIPv4 && me.seenIPv6)
664 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
666 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
667 iconPos_x += iconSize_x;
670 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
671 iconPos_x += iconSize_x;
673 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
674 iconPos_x += iconSize_x;
678 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
679 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
680 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
681 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
682 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
683 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
684 p = strstrofs(s, ":", 0);
686 s = substring(s, 0, p);
689 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
690 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
691 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
692 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
695 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
700 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
701 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
703 if(scan == K_ENTER || scan == K_KP_ENTER)
705 ServerList_Connect_Click(NULL, me);
708 else if(scan == K_MOUSE2 || scan == K_SPACE)
710 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
711 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
713 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
718 ToggleFavorite(me.selectedServer);
719 me.ipAddressBoxFocused = -1;
722 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
724 else if(!me.controlledTextbox)
727 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);