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