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, realFontSize, vector, '0 0 0')
12 ATTRIB(XonoticServerList, realUpperMargin, float, 0)
13 ATTRIB(XonoticServerList, columnIconsOrigin, float, 0)
14 ATTRIB(XonoticServerList, columnIconsSize, float, 0)
15 ATTRIB(XonoticServerList, columnPingOrigin, float, 0)
16 ATTRIB(XonoticServerList, columnPingSize, float, 0)
17 ATTRIB(XonoticServerList, columnNameOrigin, float, 0)
18 ATTRIB(XonoticServerList, columnNameSize, float, 0)
19 ATTRIB(XonoticServerList, columnMapOrigin, float, 0)
20 ATTRIB(XonoticServerList, columnMapSize, float, 0)
21 ATTRIB(XonoticServerList, columnTypeOrigin, float, 0)
22 ATTRIB(XonoticServerList, columnTypeSize, float, 0)
23 ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0)
24 ATTRIB(XonoticServerList, columnPlayersSize, float, 0)
26 ATTRIB(XonoticServerList, selectedServer, string, string_null) // to restore selected server when needed
27 METHOD(XonoticServerList, setSelected, void(entity, float))
28 METHOD(XonoticServerList, setSortOrder, void(entity, float, float))
29 ATTRIB(XonoticServerList, filterShowEmpty, float, 1)
30 ATTRIB(XonoticServerList, filterShowFull, float, 1)
31 ATTRIB(XonoticServerList, filterString, string, string_null)
32 ATTRIB(XonoticServerList, controlledTextbox, entity, NULL)
33 ATTRIB(XonoticServerList, ipAddressBox, entity, NULL)
34 ATTRIB(XonoticServerList, favoriteButton, entity, NULL)
35 ATTRIB(XonoticServerList, nextRefreshTime, float, 0)
36 METHOD(XonoticServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
37 ATTRIB(XonoticServerList, needsRefresh, float, 1)
38 METHOD(XonoticServerList, focusEnter, void(entity))
39 METHOD(XonoticServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
40 ATTRIB(XonoticServerList, sortButton1, entity, NULL)
41 ATTRIB(XonoticServerList, sortButton2, entity, NULL)
42 ATTRIB(XonoticServerList, sortButton3, entity, NULL)
43 ATTRIB(XonoticServerList, sortButton4, entity, NULL)
44 ATTRIB(XonoticServerList, sortButton5, entity, NULL)
45 ATTRIB(XonoticServerList, connectButton, entity, NULL)
46 ATTRIB(XonoticServerList, infoButton, entity, NULL)
47 ATTRIB(XonoticServerList, currentSortOrder, float, 0)
48 ATTRIB(XonoticServerList, currentSortField, float, -1)
49 ATTRIB(XonoticServerList, lastClickedServer, float, -1)
50 ATTRIB(XonoticServerList, lastClickedTime, float, 0)
52 ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1)
53 ENDCLASS(XonoticServerList)
54 entity makeXonoticServerList();
55 void ServerList_Connect_Click(entity btn, entity me);
56 void ServerList_ShowEmpty_Click(entity box, entity me);
57 void ServerList_ShowFull_Click(entity box, entity me);
58 void ServerList_Filter_Change(entity box, entity me);
59 void ServerList_Favorite_Click(entity btn, entity me);
60 void ServerList_Info_Click(entity btn, entity me);
64 float SLIST_FIELD_CNAME;
65 float SLIST_FIELD_PING;
66 float SLIST_FIELD_GAME;
67 float SLIST_FIELD_MOD;
68 float SLIST_FIELD_MAP;
69 float SLIST_FIELD_NAME;
70 float SLIST_FIELD_MAXPLAYERS;
71 float SLIST_FIELD_NUMPLAYERS;
72 float SLIST_FIELD_NUMHUMANS;
73 float SLIST_FIELD_NUMBOTS;
74 float SLIST_FIELD_PROTOCOL;
75 float SLIST_FIELD_FREESLOTS;
76 float SLIST_FIELD_PLAYERS;
77 float SLIST_FIELD_QCSTATUS;
78 float SLIST_FIELD_ISFAVORITE;
79 void ServerList_UpdateFieldIDs()
81 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
82 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
83 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
84 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
85 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
86 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
87 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
88 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
89 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
90 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
91 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
92 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
93 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
94 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
95 SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
98 float IsFavorite(string srv)
104 srv = netaddress_resolve(srv, 26000);
105 p = crypto_getidfp(srv);
106 n = tokenize_console(cvar_string("net_slist_favorites"));
107 for(i = 0; i < n; ++i)
109 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
117 if(srv == netaddress_resolve(argv(i), 26000))
124 void ToggleFavorite(string srv)
126 string s, s0, s1, s2, srv_resolved, p;
128 srv_resolved = netaddress_resolve(srv, 26000);
129 p = crypto_getidfp(srv_resolved);
130 s = cvar_string("net_slist_favorites");
131 n = tokenize_console(s);
133 for(i = 0; i < n; ++i)
135 if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
143 if(srv_resolved != netaddress_resolve(argv(i), 26000))
148 s0 = substring(s, 0, argv_end_index(i - 1));
150 s2 = substring(s, argv_start_index(i + 1), -1);
151 if(s0 != "" && s2 != "")
153 cvar_set("net_slist_favorites", strcat(s0, s1, s2));
154 s = cvar_string("net_slist_favorites");
155 n = tokenize_console(s);
166 cvar_set("net_slist_favorites", strcat(s, s1, p));
168 cvar_set("net_slist_favorites", strcat(s, s1, srv));
174 entity makeXonoticServerList()
177 me = spawnXonoticServerList();
178 me.configureXonoticServerList(me);
181 void XonoticServerList_configureXonoticServerList(entity me)
183 me.configureXonoticListBox(me);
185 ServerList_UpdateFieldIDs();
189 void XonoticServerList_setSelected(entity me, float i)
192 save = me.selectedItem;
193 SUPER(XonoticServerList).setSelected(me, i);
195 if(me.selectedItem == save)
200 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
201 return; // sorry, it would be wrong
203 if(me.selectedServer)
204 strunzone(me.selectedServer);
205 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
207 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
208 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
209 me.ipAddressBoxFocused = -1;
211 void XonoticServerList_refreshServerList(entity me, float mode)
213 // 0: just reparametrize
214 // 1: also ask for new servers
216 //print("refresh of type ", ftos(mode), "\n");
217 /* if(mode == 2) // borken
220 localcmd("net_slist\n");
221 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
226 string s, typestr, modstr;
229 m = strstrofs(s, ":", 0);
232 typestr = substring(s, 0, m);
233 s = substring(s, m + 1, strlen(s) - m - 1);
234 while(substring(s, 0, 1) == " ")
235 s = substring(s, 1, strlen(s) - 1);
240 modstr = cvar_string("menu_slist_modfilter");
242 m = SLIST_MASK_AND - 1;
243 resethostcachemasks();
244 if(!me.filterShowFull)
245 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
246 if(!me.filterShowEmpty)
247 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
249 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
252 if(substring(modstr, 0, 1) == "!")
253 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
255 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
257 m = SLIST_MASK_OR - 1;
260 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
261 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
262 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
263 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
265 o = 2; // favorites first
266 if(me.currentSortOrder < 0)
267 o |= 1; // descending
268 sethostcachesort(me.currentSortField, o);
274 void XonoticServerList_focusEnter(entity me)
276 if(time < me.nextRefreshTime)
278 //print("sorry, no refresh yet\n");
281 me.nextRefreshTime = time + 10;
282 me.refreshServerList(me, 1);
284 void XonoticServerList_draw(entity me)
286 float i, found, owned;
288 if(me.currentSortField == -1)
290 me.setSortOrder(me, SLIST_FIELD_PING, +1);
291 me.refreshServerList(me, 2);
293 else if(me.needsRefresh == 1)
295 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
297 else if(me.needsRefresh == 2)
300 me.refreshServerList(me, 0);
303 owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
305 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
307 me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
308 me.infoButton.disabled = ((me.nItems == 0) || !owned);
311 if(me.selectedServer)
313 for(i = 0; i < me.nItems; ++i)
314 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
316 if(i != me.selectedItem)
318 me.lastClickedServer = -1;
328 if(me.selectedItem >= me.nItems)
329 me.selectedItem = me.nItems - 1;
330 if(me.selectedServer)
331 strunzone(me.selectedServer);
332 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
337 if(me.selectedServer != me.ipAddressBox.text)
339 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
340 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
341 me.ipAddressBoxFocused = -1;
345 if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
347 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
349 if(IsFavorite(me.ipAddressBox.text))
350 me.favoriteButton.setText(me.favoriteButton, "Remove");
352 me.favoriteButton.setText(me.favoriteButton, "Bookmark");
354 me.ipAddressBoxFocused = me.ipAddressBox.focused;
357 SUPER(XonoticServerList).draw(me);
359 void ServerList_PingSort_Click(entity btn, entity me)
361 me.setSortOrder(me, SLIST_FIELD_PING, +1);
363 void ServerList_NameSort_Click(entity btn, entity me)
365 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
367 void ServerList_MapSort_Click(entity btn, entity me)
369 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
371 void ServerList_PlayerSort_Click(entity btn, entity me)
373 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
375 void ServerList_TypeSort_Click(entity btn, entity me)
380 m = strstrofs(s, ":", 0);
383 s = substring(s, 0, m);
384 while(substring(s, m+1, 1) == " ") // skip spaces
390 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
392 t = GametypeNameFromType(i);
394 if(t == GametypeNameFromType(0)) // it repeats (default case)
397 // choose the first one
401 if(s == GametypeNameFromType(i))
403 // the type was found
404 // choose the next one
405 s = GametypeNameFromType(i + 1);
406 if(s == GametypeNameFromType(0))
414 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
416 me.controlledTextbox.setText(me.controlledTextbox, s);
417 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
418 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
419 //ServerList_Filter_Change(me.controlledTextbox, me);
421 void ServerList_Filter_Change(entity box, entity me)
424 strunzone(me.filterString);
426 me.filterString = strzone(box.text);
428 me.filterString = string_null;
429 me.refreshServerList(me, 0);
431 me.ipAddressBox.setText(me.ipAddressBox, "");
432 me.ipAddressBox.cursorPos = 0;
433 me.ipAddressBoxFocused = -1;
435 void ServerList_ShowEmpty_Click(entity box, entity me)
437 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
438 me.refreshServerList(me, 0);
440 me.ipAddressBox.setText(me.ipAddressBox, "");
441 me.ipAddressBox.cursorPos = 0;
442 me.ipAddressBoxFocused = -1;
444 void ServerList_ShowFull_Click(entity box, entity me)
446 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
447 me.refreshServerList(me, 0);
449 me.ipAddressBox.setText(me.ipAddressBox, "");
450 me.ipAddressBox.cursorPos = 0;
451 me.ipAddressBoxFocused = -1;
453 void XonoticServerList_setSortOrder(entity me, float field, float direction)
455 if(me.currentSortField == field)
456 direction = -me.currentSortOrder;
457 me.currentSortOrder = direction;
458 me.currentSortField = field;
459 me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
460 me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
461 me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
462 me.sortButton4.forcePressed = 0;
463 me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
465 if(me.selectedServer)
466 strunzone(me.selectedServer);
467 me.selectedServer = string_null;
468 me.refreshServerList(me, 0);
470 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
472 vector originInLBSpace, sizeInLBSpace;
473 originInLBSpace = eY * (-me.itemHeight);
474 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
476 vector originInDialogSpace, sizeInDialogSpace;
477 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
478 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
480 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
481 btn.Container_size_x = sizeInDialogSpace_x * theSize;
482 btn.setText(btn, theTitle);
483 btn.onClick = theFunc;
484 btn.onClickEntity = me;
487 void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
489 SUPER(XonoticServerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
491 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
492 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
493 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
495 me.columnIconsOrigin = 0;
496 me.columnIconsSize = me.realFontSize_x * 2;
497 me.columnPingSize = me.realFontSize_x * 4;
498 me.columnMapSize = me.realFontSize_x * 12;
499 me.columnTypeSize = me.realFontSize_x * 4;
500 me.columnPlayersSize = me.realFontSize_x * 6;
501 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
502 me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
503 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
504 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
505 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
506 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
508 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
509 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
510 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
511 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);
512 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
515 f = me.currentSortField;
518 me.currentSortField = -1;
519 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
522 void ServerList_Connect_Click(entity btn, entity me)
524 if(me.ipAddressBox.text == "")
525 localcmd("connect ", me.selectedServer, "\n");
527 localcmd("connect ", me.ipAddressBox.text, "\n");
529 void ServerList_Favorite_Click(entity btn, entity me)
532 ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
535 ToggleFavorite(me.ipAddressBox.text);
536 me.ipAddressBoxFocused = -1;
539 void ServerList_Info_Click(entity btn, entity me)
541 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
542 DialogOpenButton_Click(me, main.serverInfoDialog);
544 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
546 if(i == me.lastClickedServer)
547 if(time < me.lastClickedTime + 0.3)
550 ServerList_Connect_Click(NULL, me);
552 me.lastClickedServer = i;
553 me.lastClickedTime = time;
555 void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
557 // layout: Ping, Server name, Map name, NP, TP, MP
564 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
566 if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
567 theAlpha = SKINALPHA_SERVERLIST_FULL;
568 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
569 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
573 p = gethostcachenumber(SLIST_FIELD_PING, i);
576 #define PING_HIGH 500
578 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
579 else if(p < PING_MED)
580 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
581 else if(p < PING_HIGH)
583 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
584 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
589 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
592 if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
594 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
595 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
598 s = gethostcachestring(SLIST_FIELD_CNAME, i);
599 q = stof(substring(crypto_getencryptlevel(s), 0, 1));
600 if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
602 theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
603 theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
608 if(cvar("crypto_aeslevel") >= 2)
613 if(cvar("crypto_aeslevel") >= 1)
623 // 2: AES recommended but not available
624 // 3: AES possible and will be used
625 // 4: AES recommended and will be used
628 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
632 iconSize_x = iconSize_y * (absSize_y / absSize_x);
635 iconPos_x = (me.columnIconsSize - 2 * iconSize_x) * 0.5;
636 iconPos_y = (1 - iconSize_y) * 0.5;
638 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_pure", ftos(strstrofs(s, ":P0:", 0) >= 0)), iconSize, '1 1 1', 1);
640 iconPos_x += iconSize_x;
641 draw_Picture(iconPos, strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
645 draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
646 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
647 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
648 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
649 draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
650 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
651 p = strstrofs(s, ":", 0);
653 s = substring(s, 0, p);
656 s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);
657 draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
658 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
659 draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
662 float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
667 org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
668 sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
670 if(scan == K_ENTER || scan == K_KP_ENTER)
672 ServerList_Connect_Click(NULL, me);
675 else if(scan == K_MOUSE2 || scan == K_SPACE)
677 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
678 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
680 else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
685 ToggleFavorite(me.selectedServer);
686 me.ipAddressBoxFocused = -1;
689 else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
691 else if(!me.controlledTextbox)
694 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);