]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/nexuiz/serverlist.c
made server filter work! Hooray, JOIN dialog is complete!
[divverent/nexuiz.git] / data / qcsrc / menu-div0test / 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
10         ATTRIB(NexuizServerList, realFontSize, vector, '0 0 0')
11         ATTRIB(NexuizServerList, realUpperMargin, float, 0)
12         ATTRIB(NexuizServerList, columnPingOrigin, float, 0)
13         ATTRIB(NexuizServerList, columnPingSize, float, 0)
14         ATTRIB(NexuizServerList, columnNameOrigin, float, 0)
15         ATTRIB(NexuizServerList, columnNameSize, float, 0)
16         ATTRIB(NexuizServerList, columnMapOrigin, float, 0)
17         ATTRIB(NexuizServerList, columnMapSize, float, 0)
18         ATTRIB(NexuizServerList, columnPlayersOrigin, float, 0)
19         ATTRIB(NexuizServerList, columnPlayersSize, float, 0)
20
21         ATTRIB(NexuizServerList, selectedServer, string, string_null) // to restore selected server when needed
22         METHOD(NexuizServerList, setSelected, void(entity, float))
23         METHOD(NexuizServerList, setSortOrder, void(entity, float, float))
24         ATTRIB(NexuizServerList, filterShowEmpty, float, 1)
25         ATTRIB(NexuizServerList, filterShowFull, float, 1)
26         ATTRIB(NexuizServerList, filterString, string, string_null)
27         ATTRIB(NexuizServerList, nextRefreshTime, float, 0)
28         METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
29         ATTRIB(NexuizServerList, needsRefresh, float, 1)
30         METHOD(NexuizServerList, focusEnter, void(entity))
31         METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
32         ATTRIB(NexuizServerList, sortButton1, entity, NULL)
33         ATTRIB(NexuizServerList, sortButton2, entity, NULL)
34         ATTRIB(NexuizServerList, sortButton3, entity, NULL)
35         ATTRIB(NexuizServerList, sortButton4, entity, NULL)
36         ATTRIB(NexuizServerList, connectButton, entity, NULL)
37         ATTRIB(NexuizServerList, currentSortOrder, float, 0)
38         ATTRIB(NexuizServerList, currentSortField, float, -1)
39         ATTRIB(NexuizServerList, lastClickedServer, float, -1)
40         ATTRIB(NexuizServerList, lastClickedTime, float, 0)
41 ENDCLASS(NexuizServerList)
42 entity makeNexuizServerList();
43 void ServerList_Connect_Click(entity btn, entity me);
44 void ServerList_ShowEmpty_Click(entity box, entity me);
45 void ServerList_ShowFull_Click(entity box, entity me);
46 void ServerList_Filter_Change(entity box, entity me);
47 #endif
48
49 #ifdef IMPLEMENTATION
50 float SLIST_FIELD_CNAME;
51 float SLIST_FIELD_PING;
52 float SLIST_FIELD_GAME;
53 float SLIST_FIELD_MOD;
54 float SLIST_FIELD_MAP;
55 float SLIST_FIELD_NAME;
56 float SLIST_FIELD_MAXPLAYERS;
57 float SLIST_FIELD_NUMPLAYERS;
58 float SLIST_FIELD_NUMHUMANS;
59 float SLIST_FIELD_NUMBOTS;
60 float SLIST_FIELD_PROTOCOL;
61 float SLIST_FIELD_FREESLOTS;
62 void ServerList_UpdateFieldIDs()
63 {
64         SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
65         SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
66         SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
67         SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
68         SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
69         SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
70         SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
71         SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
72         SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
73         SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
74         SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
75         SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
76 }
77
78 entity makeNexuizServerList()
79 {
80         entity me;
81         me = spawnNexuizServerList();
82         me.configureNexuizServerList(me);
83         return me;
84 }
85 void configureNexuizServerListNexuizServerList(entity me)
86 {
87         me.configureNexuizListBox(me);
88
89         ServerList_UpdateFieldIDs();
90
91         me.nItems = 0;
92 }
93 void setSelectedNexuizServerList(entity me, float i)
94 {
95         float save;
96         save = me.selectedItem;
97         setSelectedListBox(me, i);
98         /*
99         if(me.selectedItem == save)
100                 return;
101         */
102         if(me.nItems == 0)
103                 return;
104         if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
105                 return; // sorry, it would be wrong
106         if(me.selectedServer)
107                 strunzone(me.selectedServer);
108         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
109 }
110 void refreshServerListNexuizServerList(entity me, float mode)
111 {
112         // 0: just reparametrize
113         // 1: also ask for new servers
114         // 2: clear
115         print("refresh of type ", ftos(mode), "\n");
116         /* if(mode == 2) // borken
117         {
118                 // clear list
119                 localcmd("net_slist\n");
120                 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
121         }
122         else */
123         {
124                 float m;
125                 m = SLIST_MASK_AND;
126                 resethostcachemasks();
127                 if(!me.filterShowFull)
128                         sethostcachemasknumber(m++, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
129                 if(!me.filterShowEmpty)
130                         sethostcachemasknumber(m++, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
131                 m = SLIST_MASK_OR;
132                 if(me.filterString)
133                 {
134                         sethostcachemaskstring(m++, SLIST_FIELD_NAME, me.filterString, SLIST_TEST_CONTAINS);
135                         sethostcachemaskstring(m++, SLIST_FIELD_MAP, me.filterString, SLIST_TEST_CONTAINS);
136                 }
137                 sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
138                 resorthostcache();
139                 if(mode >= 1)
140                         refreshhostcache();
141         }
142 }
143 void focusEnterNexuizServerList(entity me)
144 {
145         if(time < me.nextRefreshTime)
146         {
147                 print("sorry, no refresh yet\n");
148                 return;
149         }
150         me.nextRefreshTime = time + 10;
151         me.refreshServerList(me, 1);
152 }
153 void drawNexuizServerList(entity me)
154 {
155         float i, found;
156
157         if(me.currentSortField == -1)
158         {
159                 me.setSortOrder(me, SLIST_FIELD_PING, +1);
160                 me.refreshServerList(me, 2);
161         }
162         else if(me.needsRefresh == 1)
163         {
164                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
165         }
166         else if(me.needsRefresh == 2)
167         {
168                 me.needsRefresh = 0;
169                 me.refreshServerList(me, 0);
170         }
171
172         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
173         me.connectButton.disabled = (me.nItems == 0);
174
175         found = 0;
176         if(me.selectedServer)
177         {
178                 for(i = 0; i < me.nItems; ++i)
179                         if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
180                         {
181                                 if(i != me.selectedItem)
182                                 {
183                                         me.lastClickedServer = -1;
184                                         me.selectedItem = i;
185                                 }
186                                 found = 1;
187                                 break;
188                         }
189         }
190         if(!found)
191                 if(me.nItems > 0)
192                 {
193                         if(me.selectedItem >= me.nItems)
194                                 me.selectedItem = me.nItems - 1;
195                         if(me.selectedServer)
196                                 strunzone(me.selectedServer);
197                         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
198                 }
199
200         drawListBox(me);
201 }
202 void ServerList_PingSort_Click(entity btn, entity me)
203 {
204         me.setSortOrder(me, SLIST_FIELD_PING, +1);
205 }
206 void ServerList_NameSort_Click(entity btn, entity me)
207 {
208         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
209 }
210 void ServerList_MapSort_Click(entity btn, entity me)
211 {
212         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
213 }
214 void ServerList_PlayerSort_Click(entity btn, entity me)
215 {
216         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
217 }
218 void ServerList_Filter_Change(entity box, entity me)
219 {
220         if(me.filterString)
221                 strunzone(me.filterString);
222         if(box.text != "")
223                 me.filterString = strzone(box.text);
224         else
225                 me.filterString = string_null;
226         me.refreshServerList(me, 0);
227 }
228 void ServerList_ShowEmpty_Click(entity box, entity me)
229 {
230         box.checked = me.filterShowEmpty = !me.filterShowEmpty;
231         me.refreshServerList(me, 0);
232 }
233 void ServerList_ShowFull_Click(entity box, entity me)
234 {
235         box.checked = me.filterShowFull = !me.filterShowFull;
236         me.refreshServerList(me, 0);
237 }
238 void setSortOrderNexuizServerList(entity me, float field, float direction)
239 {
240         if(me.currentSortField == field)
241                 direction = -me.currentSortOrder;
242         me.currentSortOrder = direction;
243         me.currentSortField = field;
244         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
245         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
246         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
247         me.sortButton4.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
248         me.selectedItem = 0;
249         if(me.selectedServer)
250                 strunzone(me.selectedServer);
251         me.selectedServer = string_null;
252         me.refreshServerList(me, 0);
253 }
254 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
255 {
256         vector originInLBSpace, sizeInLBSpace;
257         originInLBSpace = eY * (-me.itemHeight);
258         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
259
260         vector originInDialogSpace, sizeInDialogSpace;
261         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
262         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
263
264         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
265         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;
266         btn.setText(btn, theTitle);
267         btn.onClick = theFunc;
268         btn.onClickEntity = me;
269         btn.resized = 1;
270 }
271 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
272 {
273         resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
274
275         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
276         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
277         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
278
279         me.columnPingOrigin = 0;
280         me.columnPingSize = me.realFontSize_x * 4;
281         me.columnMapSize = me.realFontSize_x * 12;
282         me.columnPlayersSize = me.realFontSize_x * 6;
283         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - 3 * me.realFontSize_x;
284         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
285         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
286         me.columnPlayersOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
287
288         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
289         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
290         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
291         me.positionSortButton(me, me.sortButton4, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
292
293         float f;
294         f = me.currentSortField;
295         me.currentSortField = -1;
296         me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
297 }
298 void ServerList_Connect_Click(entity btn, entity me)
299 {
300         if(me.nItems > 0)
301                 localcmd("connect ", me.selectedServer, "\n");
302 }
303 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
304 {
305         if(i == me.lastClickedServer)
306                 if(time < me.lastClickedTime + 0.3)
307                 {
308                         // DOUBLE CLICK!
309                         ServerList_Connect_Click(NULL, me);
310                 }
311         me.lastClickedServer = i;
312         me.lastClickedTime = time;
313 }
314 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
315 {
316         // layout: Ping, Server name, Map name, NP, TP, MP
317         string s;
318         float p;
319         vector theColor;
320         float theAlpha;
321
322         if(isSelected)
323                 draw_Fill('0 0 0', '1 1 0', '0 0 1', 0.5);
324
325         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
326                 theAlpha = 0.2;
327         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
328                 theAlpha = 0.5;
329         else
330                 theAlpha = 1;
331         
332         p = gethostcachenumber(SLIST_FIELD_PING, i);
333         if(p < 50)
334                 theColor = eX * (p / 50) + eY;
335         else if(p < 150)
336                 theColor = eX + eY * ((150 - p) / 100);
337         else if(p < 650)
338         {
339                 theColor = eX;
340                 theAlpha *= 0.1 + 0.9 * (650 - p) / 500;
341         }
342         else
343         {
344                 theColor = eX;
345                 theAlpha *= 0.1;
346         }
347         
348         s = ftos(p);
349         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha, 0);
350         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x, 0);
351         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
352         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x, 0);
353         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);
354         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
355         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);
356 }
357 #endif