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))
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)
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, nextRefreshTime, float, 0)
32 METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
33 ATTRIB(NexuizServerList, needsRefresh, float, 1)
34 METHOD(NexuizServerList, focusEnter, void(entity))
35 METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
36 ATTRIB(NexuizServerList, sortButton1, entity, NULL)
37 ATTRIB(NexuizServerList, sortButton2, entity, NULL)
38 ATTRIB(NexuizServerList, sortButton3, entity, NULL)
39 ATTRIB(NexuizServerList, sortButton4, entity, NULL)
40 ATTRIB(NexuizServerList, sortButton5, entity, NULL)
41 ATTRIB(NexuizServerList, connectButton, entity, NULL)
42 ATTRIB(NexuizServerList, currentSortOrder, float, 0)
43 ATTRIB(NexuizServerList, currentSortField, float, -1)
44 ATTRIB(NexuizServerList, lastClickedServer, float, -1)
45 ATTRIB(NexuizServerList, lastClickedTime, float, 0)
46 ENDCLASS(NexuizServerList)
47 entity makeNexuizServerList();
48 void ServerList_Connect_Click(entity btn, entity me);
49 void ServerList_ShowEmpty_Click(entity box, entity me);
50 void ServerList_ShowFull_Click(entity box, entity me);
51 void ServerList_Filter_Change(entity box, entity me);
55 float SLIST_FIELD_CNAME;
56 float SLIST_FIELD_PING;
57 float SLIST_FIELD_GAME;
58 float SLIST_FIELD_MOD;
59 float SLIST_FIELD_MAP;
60 float SLIST_FIELD_NAME;
61 float SLIST_FIELD_MAXPLAYERS;
62 float SLIST_FIELD_NUMPLAYERS;
63 float SLIST_FIELD_NUMHUMANS;
64 float SLIST_FIELD_NUMBOTS;
65 float SLIST_FIELD_PROTOCOL;
66 float SLIST_FIELD_FREESLOTS;
67 float SLIST_FIELD_PLAYERS;
68 float SLIST_FIELD_QCSTATUS;
69 void ServerList_UpdateFieldIDs()
71 SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
72 SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
73 SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
74 SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
75 SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
76 SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
77 SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
78 SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
79 SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
80 SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
81 SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
82 SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
83 SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );
84 SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );
87 entity makeNexuizServerList()
90 me = spawnNexuizServerList();
91 me.configureNexuizServerList(me);
94 void configureNexuizServerListNexuizServerList(entity me)
96 me.configureNexuizListBox(me);
98 ServerList_UpdateFieldIDs();
102 void setSelectedNexuizServerList(entity me, float i)
105 save = me.selectedItem;
106 setSelectedListBox(me, i);
108 if(me.selectedItem == save)
113 if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
114 return; // sorry, it would be wrong
115 if(me.selectedServer)
116 strunzone(me.selectedServer);
117 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
119 void refreshServerListNexuizServerList(entity me, float mode)
121 // 0: just reparametrize
122 // 1: also ask for new servers
124 //print("refresh of type ", ftos(mode), "\n");
125 /* if(mode == 2) // borken
128 localcmd("net_slist\n");
129 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
137 m = strstrofs(s, ":", 0);
140 typestr = substring(s, 0, m);
141 s = substring(s, m + 1, strlen(s) - m - 1);
142 while(substring(s, 0, 1) == " ")
143 s = substring(s, 1, strlen(s) - 1);
148 m = SLIST_MASK_AND - 1;
149 resethostcachemasks();
150 if(!me.filterShowFull)
151 sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
152 if(!me.filterShowEmpty)
153 sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
155 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
156 m = SLIST_MASK_OR - 1;
159 sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
160 sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
161 sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
162 sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
164 sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
170 void focusEnterNexuizServerList(entity me)
172 if(time < me.nextRefreshTime)
174 //print("sorry, no refresh yet\n");
177 me.nextRefreshTime = time + 10;
178 me.refreshServerList(me, 1);
180 void drawNexuizServerList(entity me)
184 if(me.currentSortField == -1)
186 me.setSortOrder(me, SLIST_FIELD_PING, +1);
187 me.refreshServerList(me, 2);
189 else if(me.needsRefresh == 1)
191 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
193 else if(me.needsRefresh == 2)
196 me.refreshServerList(me, 0);
199 me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
200 me.connectButton.disabled = (me.nItems == 0);
203 if(me.selectedServer)
205 for(i = 0; i < me.nItems; ++i)
206 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
208 if(i != me.selectedItem)
210 me.lastClickedServer = -1;
220 if(me.selectedItem >= me.nItems)
221 me.selectedItem = me.nItems - 1;
222 if(me.selectedServer)
223 strunzone(me.selectedServer);
224 me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
229 void ServerList_PingSort_Click(entity btn, entity me)
231 me.setSortOrder(me, SLIST_FIELD_PING, +1);
233 void ServerList_NameSort_Click(entity btn, entity me)
235 me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
237 void ServerList_MapSort_Click(entity btn, entity me)
239 me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
241 void ServerList_PlayerSort_Click(entity btn, entity me)
243 me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
245 void ServerList_TypeSort_Click(entity btn, entity me)
250 m = strstrofs(s, ":", 0);
253 s = substring(s, 0, m);
254 while(substring(s, m+1, 1) == " ") // skip spaces
260 for(i = 1; ; ++i) // 20 modes ought to be enough for anyone
262 t = GametypeNameFromType(i);
264 if(t == GametypeNameFromType(0)) // it repeats (default case)
267 // choose the first one
271 if(s == GametypeNameFromType(i))
273 // the type was found
274 // choose the next one
275 s = GametypeNameFromType(i + 1);
276 if(s == GametypeNameFromType(0))
284 s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
286 me.controlledTextbox.setText(me.controlledTextbox, s);
287 me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
288 me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
289 //ServerList_Filter_Change(me.controlledTextbox, me);
291 void ServerList_Filter_Change(entity box, entity me)
294 strunzone(me.filterString);
296 me.filterString = strzone(box.text);
298 me.filterString = string_null;
299 me.refreshServerList(me, 0);
301 void ServerList_ShowEmpty_Click(entity box, entity me)
303 box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
304 me.refreshServerList(me, 0);
306 void ServerList_ShowFull_Click(entity box, entity me)
308 box.setChecked(box, me.filterShowFull = !me.filterShowFull);
309 me.refreshServerList(me, 0);
311 void setSortOrderNexuizServerList(entity me, float field, float direction)
313 if(me.currentSortField == field)
314 direction = -me.currentSortOrder;
315 me.currentSortOrder = direction;
316 me.currentSortField = field;
317 me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
318 me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
319 me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
320 me.sortButton4.forcePressed = 0;
321 me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
323 if(me.selectedServer)
324 strunzone(me.selectedServer);
325 me.selectedServer = string_null;
326 me.refreshServerList(me, 0);
328 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
330 vector originInLBSpace, sizeInLBSpace;
331 originInLBSpace = eY * (-me.itemHeight);
332 sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
334 vector originInDialogSpace, sizeInDialogSpace;
335 originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
336 sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
338 btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
339 btn.Container_size_x = sizeInDialogSpace_x * theSize;
340 btn.setText(btn, theTitle);
341 btn.onClick = theFunc;
342 btn.onClickEntity = me;
345 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
347 resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
349 me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
350 me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
351 me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
353 me.columnPingOrigin = 0;
354 me.columnPingSize = me.realFontSize_x * 4;
355 me.columnMapSize = me.realFontSize_x * 12;
356 me.columnTypeSize = me.realFontSize_x * 4;
357 me.columnPlayersSize = me.realFontSize_x * 6;
358 me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnTypeSize - 4 * me.realFontSize_x;
359 me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
360 me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
361 me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
362 me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;
364 me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
365 me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
366 me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
367 me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);
368 me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
371 f = me.currentSortField;
374 me.currentSortField = -1;
375 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
378 void ServerList_Connect_Click(entity btn, entity me)
381 localcmd("connect ", me.selectedServer, "\n");
383 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
385 if(i == me.lastClickedServer)
386 if(time < me.lastClickedTime + 0.3)
389 ServerList_Connect_Click(NULL, me);
391 me.lastClickedServer = i;
392 me.lastClickedTime = time;
394 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
396 // layout: Ping, Server name, Map name, NP, TP, MP
403 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
405 if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
406 theAlpha = SKINALPHA_SERVERLIST_FULL;
407 else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
408 theAlpha = SKINALPHA_SERVERLIST_EMPTY;
412 p = gethostcachenumber(SLIST_FIELD_PING, i);
415 #define PING_HIGH 500
417 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
418 else if(p < PING_MED)
419 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
420 else if(p < PING_HIGH)
422 theColor = SKINCOLOR_SERVERLIST_HIGHPING;
423 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
428 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
432 draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha, 0);
433 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x, 0);
434 draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
435 s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x, 0);
436 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);
437 s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
438 p = strstrofs(s, ":", 0);
440 s = substring(s, 0, p);
443 s = draw_TextShortenToWidth(s, me.columnMapSize / me.realFontSize_x, 0);
444 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);
445 s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
446 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);
449 float keyDownNexuizServerList(entity me, float scan, float ascii, float shift)
453 ServerList_Connect_Click(NULL, me);
456 else if(keyDownListBox(me, scan, ascii, shift))
458 else if(!me.controlledTextbox)
461 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);