]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu/nexuiz/serverlist.c
revert many fteqcc workarounds, as Blub has a patch to fix the bug this works around for
[divverent/nexuiz.git] / data / qcsrc / menu / nexuiz / serverlist.c
1 #ifdef INTERFACE
2 CLASS(NexuizServerList) EXTENDS(NexuizListBox)
3         METHOD(NexuizServerList, configureNexuizServerList, void(entity))
4         ATTRIB(NexuizServerList, rowsPerItem, float, 1)
5         METHOD(NexuizServerList, draw, void(entity))
6         METHOD(NexuizServerList, drawListBoxItem, void(entity, float, vector, float))
7         METHOD(NexuizServerList, clickListBoxItem, void(entity, float, vector))
8         METHOD(NexuizServerList, resizeNotify, void(entity, vector, vector, vector, vector))
9         METHOD(NexuizServerList, keyDown, float(entity, float, float, float))
10
11         ATTRIB(NexuizServerList, realFontSize, vector, '0 0 0')
12         ATTRIB(NexuizServerList, realUpperMargin, float, 0)
13         ATTRIB(NexuizServerList, columnPingOrigin, float, 0)
14         ATTRIB(NexuizServerList, columnPingSize, float, 0)
15         ATTRIB(NexuizServerList, columnNameOrigin, float, 0)
16         ATTRIB(NexuizServerList, columnNameSize, float, 0)
17         ATTRIB(NexuizServerList, columnMapOrigin, float, 0)
18         ATTRIB(NexuizServerList, columnMapSize, float, 0)
19         ATTRIB(NexuizServerList, columnTypeOrigin, float, 0)
20         ATTRIB(NexuizServerList, columnTypeSize, float, 0)
21         ATTRIB(NexuizServerList, columnPlayersOrigin, float, 0)
22         ATTRIB(NexuizServerList, columnPlayersSize, float, 0)
23
24         ATTRIB(NexuizServerList, selectedServer, string, string_null) // to restore selected server when needed
25         METHOD(NexuizServerList, setSelected, void(entity, float))
26         METHOD(NexuizServerList, setSortOrder, void(entity, float, float))
27         ATTRIB(NexuizServerList, filterShowEmpty, float, 1)
28         ATTRIB(NexuizServerList, filterShowFull, float, 1)
29         ATTRIB(NexuizServerList, filterString, string, string_null)
30         ATTRIB(NexuizServerList, controlledTextbox, entity, NULL)
31         ATTRIB(NexuizServerList, ipAddressBox, entity, NULL)
32         ATTRIB(NexuizServerList, favoriteButton, entity, NULL)
33         ATTRIB(NexuizServerList, nextRefreshTime, float, 0)
34         METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
35         ATTRIB(NexuizServerList, needsRefresh, float, 1)
36         METHOD(NexuizServerList, focusEnter, void(entity))
37         METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
38         ATTRIB(NexuizServerList, sortButton1, entity, NULL)
39         ATTRIB(NexuizServerList, sortButton2, entity, NULL)
40         ATTRIB(NexuizServerList, sortButton3, entity, NULL)
41         ATTRIB(NexuizServerList, sortButton4, entity, NULL)
42         ATTRIB(NexuizServerList, sortButton5, entity, NULL)
43         ATTRIB(NexuizServerList, connectButton, entity, NULL)
44         ATTRIB(NexuizServerList, infoButton, entity, NULL)
45         ATTRIB(NexuizServerList, currentSortOrder, float, 0)
46         ATTRIB(NexuizServerList, currentSortField, float, -1)
47         ATTRIB(NexuizServerList, lastClickedServer, float, -1)
48         ATTRIB(NexuizServerList, lastClickedTime, float, 0)
49 ENDCLASS(NexuizServerList)
50 entity makeNexuizServerList();
51 void ServerList_Connect_Click(entity btn, entity me);
52 void ServerList_ShowEmpty_Click(entity box, entity me);
53 void ServerList_ShowFull_Click(entity box, entity me);
54 void ServerList_Filter_Change(entity box, entity me);
55 void ServerList_Favorite_Click(entity btn, entity me);
56 void ServerList_Info_Click(entity btn, entity me);
57 #endif
58
59 #ifdef IMPLEMENTATION
60 float SLIST_FIELD_CNAME;
61 float SLIST_FIELD_PING;
62 float SLIST_FIELD_GAME;
63 float SLIST_FIELD_MOD;
64 float SLIST_FIELD_MAP;
65 float SLIST_FIELD_NAME;
66 float SLIST_FIELD_MAXPLAYERS;
67 float SLIST_FIELD_NUMPLAYERS;
68 float SLIST_FIELD_NUMHUMANS;
69 float SLIST_FIELD_NUMBOTS;
70 float SLIST_FIELD_PROTOCOL;
71 float SLIST_FIELD_FREESLOTS;
72 float SLIST_FIELD_PLAYERS;
73 float SLIST_FIELD_QCSTATUS;
74 float SLIST_FIELD_ISFAVORITE;
75 void ServerList_UpdateFieldIDs()
76 {
77         SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
78         SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
79         SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
80         SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
81         SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
82         SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
83         SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
84         SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
85         SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
86         SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
87         SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
88         SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
89         SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
90         SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
91         SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );
92 }
93
94 float IsFavorite(string srv)
95 {
96         string s;
97         float o;
98         s = cvar_string("net_slist_favorites");
99         s = strcat(" ", s, " ");
100         srv = strcat(" ", srv, " ");
101         o = strstrofs(s, srv, 0);
102         return (o != -1);
103 }
104
105 void ToggleFavorite(string srv)
106 {
107         string s;
108         float o;
109         s = cvar_string("net_slist_favorites");
110         o = strstrofs(strcat(" ", s, " "), strcat(" ", srv, " "), 0);
111         if(o == -1)
112         {
113                 cvar_set("net_slist_favorites", strcat(s, " ", srv));
114         }
115         else
116         {
117                 cvar_set("net_slist_favorites", strcat(
118                                         substring(s, 0, o - 1), substring(s, o + strlen(srv), strlen(s) - o - strlen(srv))
119                                         ));
120         }
121         resorthostcache();
122 }
123
124 entity makeNexuizServerList()
125 {
126         entity me;
127         me = spawnNexuizServerList();
128         me.configureNexuizServerList(me);
129         return me;
130 }
131 void configureNexuizServerListNexuizServerList(entity me)
132 {
133         me.configureNexuizListBox(me);
134
135         ServerList_UpdateFieldIDs();
136
137         me.nItems = 0;
138 }
139 void setSelectedNexuizServerList(entity me, float i)
140 {
141         float save;
142         save = me.selectedItem;
143         setSelectedListBox(me, i);
144         /*
145         if(me.selectedItem == save)
146                 return;
147         */
148         if(me.nItems == 0)
149                 return;
150         if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
151                 return; // sorry, it would be wrong
152
153         if(me.selectedServer)
154                 strunzone(me.selectedServer);
155         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
156
157         me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
158         me.ipAddressBox.cursorPos = strlen(me.selectedServer);
159 }
160 void refreshServerListNexuizServerList(entity me, float mode)
161 {
162         // 0: just reparametrize
163         // 1: also ask for new servers
164         // 2: clear
165         //print("refresh of type ", ftos(mode), "\n");
166         /* if(mode == 2) // borken
167         {
168                 // clear list
169                 localcmd("net_slist\n");
170                 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
171         }
172         else */
173         {
174                 float m, o;
175                 string s, typestr, modstr;
176                 s = me.filterString;
177
178                 m = strstrofs(s, ":", 0);
179                 if(m >= 0)
180                 {
181                         typestr = substring(s, 0, m);
182                         s = substring(s, m + 1, strlen(s) - m - 1);
183                         while(substring(s, 0, 1) == " ")
184                                 s = substring(s, 1, strlen(s) - 1);
185                 }
186                 else
187                         typestr = "";
188
189                 modstr = cvar_string("menu_slist_modfilter");
190
191                 m = SLIST_MASK_AND - 1;
192                 resethostcachemasks();
193                 if(!me.filterShowFull)
194                         sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
195                 if(!me.filterShowEmpty)
196                         sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
197                 if(typestr != "")
198                         sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
199                 if(modstr != "")
200                 {
201                         if(substring(modstr, 0, 1) == "!")
202                                 sethostcachemaskstring(++m, SLIST_FIELD_MOD, substring(modstr, 1, strlen(modstr) - 1), SLIST_TEST_NOTEQUAL);
203                         else
204                                 sethostcachemaskstring(++m, SLIST_FIELD_MOD, modstr, SLIST_TEST_EQUAL);
205                 }
206                 m = SLIST_MASK_OR - 1;
207                 if(s != "")
208                 {
209                         sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
210                         sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
211                         sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
212                         sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
213                 }
214                 o = 2; // favorites first
215                 if(me.currentSortOrder < 0)
216                         o |= 1; // descending
217                 sethostcachesort(me.currentSortField, o);
218                 resorthostcache();
219                 if(mode >= 1)
220                         refreshhostcache();
221         }
222 }
223 void focusEnterNexuizServerList(entity me)
224 {
225         if(time < me.nextRefreshTime)
226         {
227                 //print("sorry, no refresh yet\n");
228                 return;
229         }
230         me.nextRefreshTime = time + 10;
231         me.refreshServerList(me, 1);
232 }
233 void drawNexuizServerList(entity me)
234 {
235         float i, found, owned;
236
237         if(me.currentSortField == -1)
238         {
239                 me.setSortOrder(me, SLIST_FIELD_PING, +1);
240                 me.refreshServerList(me, 2);
241         }
242         else if(me.needsRefresh == 1)
243         {
244                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
245         }
246         else if(me.needsRefresh == 2)
247         {
248                 me.needsRefresh = 0;
249                 me.refreshServerList(me, 0);
250         }
251
252         owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
253
254         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
255
256         me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
257         me.infoButton.disabled = ((me.nItems == 0) || !owned);
258
259         found = 0;
260         if(me.selectedServer)
261         {
262                 for(i = 0; i < me.nItems; ++i)
263                         if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
264                         {
265                                 if(i != me.selectedItem)
266                                 {
267                                         me.lastClickedServer = -1;
268                                         me.selectedItem = i;
269                                 }
270                                 found = 1;
271                                 break;
272                         }
273         }
274         if(!found)
275                 if(me.nItems > 0)
276                 {
277                         if(me.selectedItem >= me.nItems)
278                                 me.selectedItem = me.nItems - 1;
279                         if(me.selectedServer)
280                                 strunzone(me.selectedServer);
281                         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
282                 }
283
284         if(owned)
285         {
286                 me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
287                 me.ipAddressBox.cursorPos = strlen(me.selectedServer);
288         }
289
290         if(IsFavorite(me.ipAddressBox.text))
291                 me.favoriteButton.setText(me.favoriteButton, "Remove");
292         else
293                 me.favoriteButton.setText(me.favoriteButton, "Bookmark");
294
295         drawListBox(me);
296 }
297 void ServerList_PingSort_Click(entity btn, entity me)
298 {
299         me.setSortOrder(me, SLIST_FIELD_PING, +1);
300 }
301 void ServerList_NameSort_Click(entity btn, entity me)
302 {
303         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
304 }
305 void ServerList_MapSort_Click(entity btn, entity me)
306 {
307         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
308 }
309 void ServerList_PlayerSort_Click(entity btn, entity me)
310 {
311         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
312 }
313 void ServerList_TypeSort_Click(entity btn, entity me)
314 {
315         string s, t;
316         float i, m;
317         s = me.filterString;
318         m = strstrofs(s, ":", 0);
319         if(m >= 0)
320         {
321                 s = substring(s, 0, m);
322                 while(substring(s, m+1, 1) == " ") // skip spaces
323                         ++m;
324         }
325         else
326                 s = "";
327
328         for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
329         {
330                 t = GametypeNameFromType(i);
331                 if(i > 1)
332                         if(t == GametypeNameFromType(0)) // it repeats (default case)
333                         {
334                                 // no type was found
335                                 // choose the first one
336                                 s = t;
337                                 break;
338                         }
339                 if(s == GametypeNameFromType(i))
340                 {
341                         // the type was found
342                         // choose the next one
343                         s = GametypeNameFromType(i + 1);
344                         if(s == GametypeNameFromType(0))
345                                 s = "";
346                         break;
347                 }
348         }
349
350         if(s != "")
351                 s = strcat(s, ":");
352         s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
353
354         me.controlledTextbox.setText(me.controlledTextbox, s);
355         me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
356         me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
357         //ServerList_Filter_Change(me.controlledTextbox, me);
358 }
359 void ServerList_Filter_Change(entity box, entity me)
360 {
361         if(me.filterString)
362                 strunzone(me.filterString);
363         if(box.text != "")
364                 me.filterString = strzone(box.text);
365         else
366                 me.filterString = string_null;
367         me.refreshServerList(me, 0);
368
369         me.ipAddressBox.setText(me.ipAddressBox, "");
370         me.ipAddressBox.cursorPos = 0;
371 }
372 void ServerList_ShowEmpty_Click(entity box, entity me)
373 {
374         box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
375         me.refreshServerList(me, 0);
376
377         me.ipAddressBox.setText(me.ipAddressBox, "");
378         me.ipAddressBox.cursorPos = 0;
379 }
380 void ServerList_ShowFull_Click(entity box, entity me)
381 {
382         box.setChecked(box, me.filterShowFull = !me.filterShowFull);
383         me.refreshServerList(me, 0);
384
385         me.ipAddressBox.setText(me.ipAddressBox, "");
386         me.ipAddressBox.cursorPos = 0;
387 }
388 void setSortOrderNexuizServerList(entity me, float field, float direction)
389 {
390         if(me.currentSortField == field)
391                 direction = -me.currentSortOrder;
392         me.currentSortOrder = direction;
393         me.currentSortField = field;
394         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
395         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
396         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
397         me.sortButton4.forcePressed = 0;
398         me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
399         me.selectedItem = 0;
400         if(me.selectedServer)
401                 strunzone(me.selectedServer);
402         me.selectedServer = string_null;
403         me.refreshServerList(me, 0);
404 }
405 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
406 {
407         vector originInLBSpace, sizeInLBSpace;
408         originInLBSpace = eY * (-me.itemHeight);
409         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
410
411         vector originInDialogSpace, sizeInDialogSpace;
412         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
413         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
414
415         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
416         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;
417         btn.setText(btn, theTitle);
418         btn.onClick = theFunc;
419         btn.onClickEntity = me;
420         btn.resized = 1;
421 }
422 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
423 {
424         resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
425
426         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
427         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
428         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
429
430         me.columnPingOrigin = 0;
431         me.columnPingSize = me.realFontSize_x * 4;
432         me.columnMapSize = me.realFontSize_x * 12;
433         me.columnTypeSize = me.realFontSize_x * 4;
434         me.columnPlayersSize = me.realFontSize_x * 6;
435         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnTypeSize - 4 * me.realFontSize_x;
436         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
437         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
438         me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
439         me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
440
441         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
442         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
443         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
444         me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);
445         me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
446
447         float f;
448         f = me.currentSortField;
449         if(f >= 0)
450         {
451                 me.currentSortField = -1;
452                 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
453         }
454 }
455 void ServerList_Connect_Click(entity btn, entity me)
456 {
457         if(me.ipAddressBox.text == "")
458                 localcmd("connect ", me.selectedServer, "\n");
459         else
460                 localcmd("connect ", me.ipAddressBox.text, "\n");
461 }
462 void ServerList_Favorite_Click(entity btn, entity me)
463 {
464         string ipstr;
465         ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
466         if(ipstr != "")
467         {
468                 me.ipAddressBox.setText(me.ipAddressBox, ipstr);
469                 me.ipAddressBox.cursorPos = strlen(ipstr);
470                 ToggleFavorite(ipstr);
471         }
472 }
473 void ServerList_Info_Click(entity btn, entity me)
474 {
475         main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
476         DialogOpenButton_Click(me, main.serverInfoDialog);
477 }
478 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
479 {
480         if(i == me.lastClickedServer)
481                 if(time < me.lastClickedTime + 0.3)
482                 {
483                         // DOUBLE CLICK!
484                         ServerList_Connect_Click(NULL, me);
485                 }
486         me.lastClickedServer = i;
487         me.lastClickedTime = time;
488 }
489 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
490 {
491         // layout: Ping, Server name, Map name, NP, TP, MP
492         string s;
493         float p;
494         vector theColor;
495         float theAlpha;
496
497         if(isSelected)
498                 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
499
500         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
501                 theAlpha = SKINALPHA_SERVERLIST_FULL;
502         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
503                 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
504         else
505                 theAlpha = 1;
506
507         p = gethostcachenumber(SLIST_FIELD_PING, i);
508 #define PING_LOW 75
509 #define PING_MED 200
510 #define PING_HIGH 500
511         if(p < PING_LOW)
512                 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
513         else if(p < PING_MED)
514                 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
515         else if(p < PING_HIGH)
516         {
517                 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
518                 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
519         }
520         else
521         {
522                 theColor = eX;
523                 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
524         }
525
526         if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
527         {
528                 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
529                 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
530         }
531
532         s = ftos(p);
533         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha, 0);
534         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x, 0);
535         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
536         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x, 0);
537         draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
538         s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
539         p = strstrofs(s, ":", 0);
540         if(p >= 0)
541                 s = substring(s, 0, p);
542         else
543                 s = "";
544         s = draw_TextShortenToWidth(s, me.columnMapSize / me.realFontSize_x, 0);
545         draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
546         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
547         draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
548 }
549
550 float keyDownNexuizServerList(entity me, float scan, float ascii, float shift)
551 {
552         float i;
553         vector org, sz;
554
555         org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
556         sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
557
558         if(scan == K_ENTER)
559         {
560                 ServerList_Connect_Click(NULL, me);
561                 return 1;
562         }
563         else if(scan == K_MOUSE2 || scan == K_SPACE)
564         {
565                 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
566                 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
567         }
568         else if(scan == K_INS || scan == K_MOUSE3)
569         {
570                 i = me.selectedItem;
571                 if(i < me.nItems)
572                         ToggleFavorite(me.selectedServer);
573         }
574         else if(keyDownListBox(me, scan, ascii, shift))
575                 return 1;
576         else if(!me.controlledTextbox)
577                 return 0;
578         else
579                 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
580 }
581 #endif