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);
112 p = crypto_getidfp(srv);
113 n = tokenize_console(cvar_string("net_slist_favorites"));
114 for(i = 0; i < n; ++i)
116 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
124 if(srv == netaddress_resolve(argv(i), 26000))
131 void ToggleFavorite(string srv)
133 string s, s0, s1, s2, srv_resolved, p;
135 srv_resolved = netaddress_resolve(srv, 26000);
136 p = crypto_getidfp(srv_resolved);
137 s = cvar_string("net_slist_favorites");
138 n = tokenize_console(s);
140 for(i = 0; i < n; ++i)
142 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
150 if(srv_resolved != netaddress_resolve(argv(i), 26000))
155 s0 = substring(s, 0, argv_end_index(i - 1));
157 s2 = substring(s, argv_start_index(i + 1), -1);
158 if(s0 != "" && s2 != "")
160 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
161 s = cvar_string("net_slist_favorites");
162 n = tokenize_console(s);
173 cvar_set("net_slist_favorites", strcat(s, s1, p));
175 cvar_set("net_slist_favorites", strcat(s, s1, srv));
181 entity makeXonoticServerList()
184 me = spawnXonoticServerList();
185 me.configureXonoticServerList(me);
188 void XonoticServerList_configureXonoticServerList(entity me)
190 me.configureXonoticListBox(me);
192 ServerList_UpdateFieldIDs();
196 void XonoticServerList_setSelected(entity me, float i)
199 save = me.selectedItem;
200 SUPER(XonoticServerList).setSelected(me, i);
202 if(me.selectedItem == save)
207 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
208 return; // sorry, it would be wrong
210 if(me.selectedServer)
211 strunzone(me.selectedServer);
212 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
214 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
215 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
216 me.ipAddressBoxFocused = -1;
218 void XonoticServerList_refreshServerList(entity me, float mode)
220 // 0: just reparametrize
221 // 1: also ask for new servers
223 //print("refresh of type ", ftos(mode), "\n");
224 /* if(mode == 2) // borken
227 localcmd("net_slist\n");
228 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
233 string s, typestr, modstr;
236 m = strstrofs(s, ":", 0);
239 typestr = substring(s, 0, m);
240 s = substring(s, m + 1, strlen(s) - m - 1);
241 while(substring(s, 0, 1) == " ")
242 s = substring(s, 1, strlen(s) - 1);
247 modstr = cvar_string("menu_slist_modfilter");
249 m = SLIST_MASK_AND - 1;
250 resethostcachemasks();
251 if(!me.filterShowFull)
252 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
253 if(!me.filterShowEmpty)
254 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
256 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
259 if(substring(modstr, 0, 1) == "!")
260 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
262 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
264 m = SLIST_MASK_OR - 1;
267 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
268 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
269 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
270 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
272 o = 2; // favorites first
273 if(me.currentSortOrder < 0)
274 o |= 1; // descending
275 sethostcachesort(me.currentSortField, o);
281 void XonoticServerList_focusEnter(entity me)
283 if(time < me.nextRefreshTime)
285 //print("sorry, no refresh yet\n");
288 me.nextRefreshTime = time + 10;
289 me.refreshServerList(me, 1);
291 void XonoticServerList_draw(entity me)
293 float i, found, owned;
295 if(me.currentSortField == -1)
297 me.setSortOrder(me, SLIST_FIELD_PING, +1);
298 me.refreshServerList(me, 2);
300 else if(me.needsRefresh == 1)
302 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
304 else if(me.needsRefresh == 2)
307 me.refreshServerList(me, 0);
310 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
312 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
314 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
315 me.infoButton.disabled = ((me.nItems == 0) || !owned);
318 if(me.selectedServer)
320 for(i = 0; i < me.nItems; ++i)
321 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
323 if(i != me.selectedItem)
325 me.lastClickedServer = -1;
335 if(me.selectedItem >= me.nItems)
336 me.selectedItem = me.nItems - 1;
337 if(me.selectedServer)
338 strunzone(me.selectedServer);
339 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
344 if(me.selectedServer != me.ipAddressBox.text)
346 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
347 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
348 me.ipAddressBoxFocused = -1;
352 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
354 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
356 if(IsFavorite(me.ipAddressBox.text))
357 me.favoriteButton.setText(me.favoriteButton, "Remove");
359 me.favoriteButton.setText(me.favoriteButton, "Bookmark");
361 me.ipAddressBoxFocused = me.ipAddressBox.focused;
364 SUPER(XonoticServerList).draw(me);
366 void ServerList_PingSort_Click(entity btn, entity me)
368 me.setSortOrder(me, SLIST_FIELD_PING, +1);
370 void ServerList_NameSort_Click(entity btn, entity me)
372 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
374 void ServerList_MapSort_Click(entity btn, entity me)
376 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
378 void ServerList_PlayerSort_Click(entity btn, entity me)
380 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
382 void ServerList_TypeSort_Click(entity btn, entity me)
387 m = strstrofs(s, ":", 0);
390 s = substring(s, 0, m);
391 while(substring(s, m+1, 1) == " ") // skip spaces
397 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
399 t = GametypeNameFromType(i);
401 if(t == GametypeNameFromType(0)) // it repeats (default case)
404 // choose the first one
408 if(s == GametypeNameFromType(i))
410 // the type was found
411 // choose the next one
412 s = GametypeNameFromType(i + 1);
413 if(s == GametypeNameFromType(0))
421 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
423 me.controlledTextbox.setText(me.controlledTextbox, s);
424 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
425 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
426 //ServerList_Filter_Change(me.controlledTextbox, me);
428 void ServerList_Filter_Change(entity box, entity me)
431 strunzone(me.filterString);
433 me.filterString = strzone(box.text);
435 me.filterString = string_null;
436 me.refreshServerList(me, 0);
438 me.ipAddressBox.setText(me.ipAddressBox, "");
439 me.ipAddressBox.cursorPos = 0;
440 me.ipAddressBoxFocused = -1;
442 void ServerList_ShowEmpty_Click(entity box, entity me)
444 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
445 me.refreshServerList(me, 0);
447 me.ipAddressBox.setText(me.ipAddressBox, "");
448 me.ipAddressBox.cursorPos = 0;
449 me.ipAddressBoxFocused = -1;
451 void ServerList_ShowFull_Click(entity box, entity me)
453 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
454 me.refreshServerList(me, 0);
456 me.ipAddressBox.setText(me.ipAddressBox, "");
457 me.ipAddressBox.cursorPos = 0;
458 me.ipAddressBoxFocused = -1;
460 void XonoticServerList_setSortOrder(entity me, float field, float direction)
462 if(me.currentSortField == field)
463 direction = -me.currentSortOrder;
464 me.currentSortOrder = direction;
465 me.currentSortField = field;
466 me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
467 me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
468 me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
469 me.sortButton4.forcePressed = 0;
470 me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
472 if(me.selectedServer)
473 strunzone(me.selectedServer);
474 me.selectedServer = string_null;
475 me.refreshServerList(me, 0);
477 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
479 vector originInLBSpace, sizeInLBSpace;
480 originInLBSpace = eY * (-me.itemHeight);
481 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
483 vector originInDialogSpace, sizeInDialogSpace;
484 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
485 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
487 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
488 btn.Container_size_x = sizeInDialogSpace_x * theSize;
489 btn.setText(btn, theTitle);
490 btn.onClick = theFunc;
491 btn.onClickEntity = me;
494 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
496 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
498 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
499 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
500 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
502 me.columnIconsOrigin = 0;
503 me.columnIconsSize = me.realFontSize_x * 3 * me.iconsSizeFactor;
504 me.columnPingSize = me.realFontSize_x * 3;
505 me.columnMapSize = me.realFontSize_x * 10;
506 me.columnTypeSize = me.realFontSize_x * 4;
507 me.columnPlayersSize = me.realFontSize_x * 5;
508 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
509 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
510 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
511 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
512 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
513 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
515 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
516 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
517 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
518 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);
519 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
522 f = me.currentSortField;
525 me.currentSortField = -1;
526 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
529 void ServerList_Connect_Click(entity btn, entity me)
531 if(me.ipAddressBox.text == "")
532 localcmd("connect ", me.selectedServer, "\n");
534 localcmd("connect ", me.ipAddressBox.text, "\n");
536 void ServerList_Favorite_Click(entity btn, entity me)
539 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
542 ToggleFavorite(me.ipAddressBox.text);
543 me.ipAddressBoxFocused = -1;
546 void ServerList_Info_Click(entity btn, entity me)
548 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
549 DialogOpenButton_Click(me, main.serverInfoDialog);
551 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
553 if(i == me.lastClickedServer)
554 if(time < me.lastClickedTime + 0.3)
557 ServerList_Connect_Click(NULL, me);
559 me.lastClickedServer = i;
560 me.lastClickedTime = time;
562 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
564 // layout: Ping, Server name, Map name, NP, TP, MP
572 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
574 if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
575 theAlpha = SKINALPHA_SERVERLIST_FULL;
576 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
577 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
581 p = gethostcachenumber(SLIST_FIELD_PING, i);
584 #define PING_HIGH 500
586 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
587 else if(p < PING_MED)
588 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
589 else if(p < PING_HIGH)
591 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
592 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
597 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
600 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
602 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
603 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
606 s = gethostcachestring(SLIST_FIELD_CNAME, i);
609 if(substring(s, 0, 1) == "[")
614 else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
620 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
621 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
623 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
624 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
629 if(cvar("crypto_aeslevel") >= 2)
634 if(cvar("crypto_aeslevel") >= 1)
644 // 2: AES recommended but not available
645 // 3: AES possible and will be used
646 // 4: AES recommended and will be used
649 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
652 iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
653 iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
656 iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
657 iconPos_y = (1 - iconSize_y) * 0.5;
659 if not(me.seenIPv4 && me.seenIPv6)
661 iconPos_x += iconSize_x * 0.5;
663 else if(me.seenIPv4 && me.seenIPv6)
666 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), iconSize, '1 1 1', 1);
668 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), iconSize, '1 1 1', 1);
669 iconPos_x += iconSize_x;
672 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
673 iconPos_x += iconSize_x;
675 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
676 iconPos_x += iconSize_x;
680 draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
681 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
682 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
683 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
684 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
685 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
686 p = strstrofs(s, ":", 0);
688 s = substring(s, 0, p);
691 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
692 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
693 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
694 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
697 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
702 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
703 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
705 if(scan == K_ENTER || scan == K_KP_ENTER)
707 ServerList_Connect_Click(NULL, me);
710 else if(scan == K_MOUSE2 || scan == K_SPACE)
714 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
715 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
718 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
723 ToggleFavorite(me.selectedServer);
724 me.ipAddressBoxFocused = -1;
727 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
729 else if(!me.controlledTextbox)
732 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);