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