]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/client/mapvoting.qc
Include gmqcc binaries for Windows and Linux
[voretournament/voretournament.git] / data / qcsrc / client / mapvoting.qc
1 float mv_num_maps;\r
2 \r
3 float mv_active;\r
4 string mv_maps[MAPVOTE_COUNT];\r
5 string mv_pics[MAPVOTE_COUNT];\r
6 string mv_pk3[MAPVOTE_COUNT];\r
7 float mv_preview[MAPVOTE_COUNT];\r
8 float mv_votes[MAPVOTE_COUNT];\r
9 entity mv_pk3list;\r
10 float mv_abstain;\r
11 float mv_ownvote;\r
12 float mv_detail;\r
13 float mv_timeout;\r
14 float mv_maps_mask;\r
15 \r
16 vector mv_mousepos;\r
17 float mv_selection;\r
18 \r
19 string MapVote_FormatMapItem(float id, string map, float count, float maxwidth, vector fontsize)\r
20 {\r
21         string pre, post;\r
22         pre = strcat(ftos(id+1), ". ");\r
23         if(mv_detail)\r
24         {\r
25                 if(count == 1)\r
26                         post = strcat(" (1 vote)");\r
27                 else\r
28                         post = strcat(" (", ftos(count), " votes)");\r
29         }\r
30         else\r
31                 post = "";\r
32         maxwidth -= stringwidth(pre, FALSE, fontsize) + stringwidth(post, FALSE, fontsize);\r
33         map = textShortenToWidth(map, maxwidth, fontsize, stringwidth_nocolors);\r
34         return strcat(pre, map, post);\r
35 }\r
36 \r
37 vector MapVote_RGB(float id)\r
38 {\r
39         if(id == mv_ownvote)\r
40                 return '0 1 0';\r
41         else if (id == mv_selection)\r
42                 return '1 1 0';\r
43         else\r
44                 return '1 1 1';\r
45 }\r
46 \r
47 void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float count, float id)\r
48 {\r
49         vector img_size;\r
50         vector rgb;\r
51         string label;\r
52         float text_size;\r
53         \r
54         isize -= sbar_fontsize_y; // respect the text when calculating the image size\r
55 \r
56         rgb = MapVote_RGB(id);\r
57         \r
58         img_size_y = isize;\r
59         img_size_x = isize / 0.75; // 4:3 x can be stretched easily, height is defined in isize\r
60 \r
61         drawfont = sbar_font;\r
62         pos_y = pos_y + img_size_y;\r
63         \r
64         label = MapVote_FormatMapItem(id, map, count, tsize, sbar_fontsize);\r
65 \r
66         text_size = stringwidth(label, false, sbar_fontsize);\r
67         \r
68         pos_x -= text_size*0.5;\r
69         drawstring(pos, label, sbar_fontsize, rgb, 1, DRAWFLAG_NORMAL);\r
70         \r
71         pos_x = pos_x + text_size*0.5 - img_size_x*0.5;\r
72         pos_y = pos_y - img_size_y;\r
73 \r
74         pos += sbar_border_thickness * '1 1 0';\r
75         img_size -= (sbar_border_thickness * 2) * '1 1 0';\r
76         if(pic == "")\r
77         {\r
78                 if(drawgetimagesize(pic) == '0 0 0')\r
79                         drawpic(pos, draw_UseSkinFor("nopreview_map"), img_size, '1 1 1', 0.7, DRAWFLAG_NORMAL);\r
80                 else\r
81                         drawpic(pos, pic, img_size, '1 1 1', 0.7, DRAWFLAG_NORMAL);\r
82         }\r
83         else\r
84         {\r
85                 drawpic(pos, pic, img_size, '1 1 1', 1, DRAWFLAG_NORMAL);\r
86         }\r
87         \r
88         drawstring(pos + '2 0 0', ftos(id+1), (img_size_y / 5) * '1 1 0', '1 1 1', 0.6, DRAWFLAG_NORMAL);\r
89 \r
90         if(id == mv_ownvote || pic == "")\r
91         {\r
92                 drawborderlines(sbar_border_thickness, pos, img_size, rgb, 1, DRAWFLAG_NORMAL);\r
93                 drawstring(pos + '2 0 0', ftos(id+1), (img_size_y / 5) * '1 1 0', rgb, 0.6, DRAWFLAG_NORMAL);\r
94         }\r
95         else\r
96         {\r
97                 drawborderlines(sbar_border_thickness, pos, img_size, '0 0 0', 1, DRAWFLAG_NORMAL);\r
98                 drawstring(pos + '2 0 0', ftos(id+1), (img_size_y / 5) * '1 1 0', '1 1 1', 0.6, DRAWFLAG_NORMAL);\r
99         }\r
100 }\r
101 \r
102 void MapVote_DrawAbstain(vector pos, float isize, float tsize, float count, float id)\r
103 {\r
104         vector rgb;\r
105         float text_size;\r
106         string label;\r
107         \r
108         rgb = MapVote_RGB(id);\r
109 \r
110         drawfont = sbar_font;\r
111         pos_y = pos_y + sbar_fontsize_y;\r
112         \r
113         label = MapVote_FormatMapItem(id, "Don't care", count, tsize, sbar_fontsize);\r
114 \r
115         text_size = stringwidth(label, false, sbar_fontsize);\r
116         \r
117         pos_x -= text_size*0.5;\r
118         drawstring(pos, label, sbar_fontsize, rgb, 1, DRAWFLAG_NORMAL);\r
119 }\r
120 \r
121 vector MapVote_GridVec(vector gridspec, float i, float m)\r
122 {\r
123         float r;\r
124         r = mod(i, m);\r
125         return\r
126                 '1 0 0' * (gridspec_x * r)\r
127                 +\r
128                 '0 1 0' * (gridspec_y * (i - r) / m);\r
129 }\r
130 \r
131 float MapVote_Selection(vector topleft, vector cellsize, float rows, float columns)\r
132 {\r
133         float cell;\r
134         float c, r;\r
135 \r
136         cell = -1;\r
137 \r
138         for (r = 0; r < rows; ++r)\r
139                 for (c = 0; c < columns; ++c)\r
140                 {\r
141                         if (mv_mousepos_x >= topleft_x + cellsize_x *  c &&\r
142                                 mv_mousepos_x <= topleft_x + cellsize_x * (c + 1) &&\r
143                                 mv_mousepos_y >= topleft_y + cellsize_y *  r &&\r
144                                 mv_mousepos_y <= topleft_y + cellsize_y * (r + 1))\r
145                         {\r
146                                 cell = r * columns + c;\r
147                                 break;\r
148                         }\r
149                 }\r
150 \r
151         if (cell >= mv_num_maps)\r
152                 cell = -1;\r
153 \r
154         if (mv_abstain && cell < 0)\r
155                 return mv_num_maps;\r
156 \r
157         return cell;\r
158 }\r
159 \r
160 void MapVote_Draw()\r
161 {\r
162         string map;\r
163         float i, tmp;\r
164         vector pos;\r
165         float isize;\r
166         float center;\r
167         float columns, rows;\r
168         float tsize;\r
169         vector dist;\r
170 \r
171         if(!mv_active)\r
172                 return;\r
173         \r
174         mv_mousepos = mv_mousepos + getmousepos();\r
175 \r
176         mv_mousepos_x = bound(0, mv_mousepos_x, vid_conwidth);\r
177         mv_mousepos_y = bound(0, mv_mousepos_y, vid_conheight);\r
178 \r
179         center = (vid_conwidth - 1)/2;\r
180         xmin = vid_conwidth*0.05; // 5% border must suffice\r
181         xmax = vid_conwidth - xmin;\r
182         ymin = 20;\r
183         i = cvar("con_chatpos"); //*cvar("con_chatsize");\r
184         if(i < 0)\r
185                 ymax = vid_conheight + (i - cvar("con_chat")) * cvar("con_chatsize");\r
186         if(i >= 0 || ymax < (vid_conheight*0.5))\r
187                 ymax = vid_conheight - ymin;\r
188 \r
189         drawfont = sbar_bigfont;\r
190         sbar_fontsize = Sbar_GetFontsize("sbar_fontsize");\r
191 \r
192         pos_y = ymin;\r
193         pos_z = 0;\r
194         //pos_x = center - stringwidth("Vote for a map", false) * 0.5 * 24;\r
195         pos_x = center - stringwidth("Vote for a map", false, '12 0 0');\r
196         drawstring(pos, "Vote for a map", '24 24 0', '1 1 1', 1, DRAWFLAG_NORMAL);\r
197         pos_y += 26;\r
198 \r
199         i = ceil(max(0, mv_timeout - time));\r
200         map = strcat(ftos(i), " seconds left");\r
201         //pos_x = center - stringwidth(map, false) * 0.5 * 16;\r
202         pos_x = center - stringwidth(map, false, '8 0 0');\r
203         drawstring(pos, map, '16 16 0', '0 1 0', 1, DRAWFLAG_NORMAL);\r
204         pos_y += 22;\r
205         pos_x = xmin;\r
206 \r
207         drawfont = sbar_font;\r
208         \r
209         // base for multi-column stuff...\r
210         ymin = pos_y;\r
211         if(mv_abstain)\r
212                 mv_num_maps -= 1;\r
213         \r
214         if(mv_num_maps > 3)\r
215         {\r
216                 columns = 3;\r
217         } else {\r
218                 columns = mv_num_maps;\r
219         }\r
220         rows = ceil(mv_num_maps / columns);\r
221 \r
222         dist_x = (xmax - xmin) / columns;\r
223         dist_y = (ymax - pos_y) / rows;\r
224         tsize = dist_x - 10;\r
225         isize = min(dist_y - 10, 0.75 * tsize);\r
226 \r
227         mv_selection = MapVote_Selection(pos, dist, rows, columns);\r
228 \r
229         pos_x += (xmax - xmin) / (2 * columns);\r
230         pos_y += (dist_y - isize) / 2;\r
231         ymax -= isize;\r
232 \r
233         for(i = 0; i < mv_num_maps; ++i)\r
234         {\r
235                 tmp = mv_votes[i]; // FTEQCC bug: too many array accesses in the function call screw it up\r
236                 if(tmp < 0)\r
237                         continue;\r
238                 map = mv_maps[i];\r
239                 if(mv_preview[i])\r
240                         MapVote_DrawMapItem(pos + MapVote_GridVec(dist, i, columns), isize, tsize, map, mv_pics[i], tmp, i);\r
241                 else\r
242                         MapVote_DrawMapItem(pos + MapVote_GridVec(dist, i, columns), isize, tsize, map, "", tmp, i);\r
243         }\r
244 \r
245         if(mv_abstain)\r
246                 ++mv_num_maps;\r
247         \r
248         if(mv_abstain && i < mv_num_maps) {\r
249                 tmp = mv_votes[i];\r
250                 pos_y = ymax + isize - sbar_fontsize_y;\r
251                 pos_x = (xmax+xmin)*0.5;\r
252                 MapVote_DrawAbstain(pos, isize, xmax - xmin, tmp, i);\r
253         }\r
254 \r
255         drawpic(mv_mousepos, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor.tga"), '32 32 0', '1 1 1', sbar_alpha_fg, DRAWFLAG_NORMAL);\r
256 }\r
257 \r
258 void Cmd_MapVote_MapDownload(float argc)\r
259 {\r
260         float id;\r
261         entity pak;\r
262 \r
263         if(argc != 2 || !mv_pk3list)\r
264         {\r
265                 print("mv_mapdownload: ^3You're not supposed to use this command on your own!\n");\r
266                 return;\r
267         }\r
268         \r
269         id = stof(argv(1));\r
270         for(pak = mv_pk3list; pak; pak = pak.chain)\r
271                 if(pak.sv_entnum == id)\r
272                         break;\r
273         \r
274         if(!pak || pak.sv_entnum != id) {\r
275                 print("^1Error:^7 Couldn't find pak index.\n");\r
276                 return;\r
277         }\r
278 \r
279         //print(strcat("^3Adding: ", ftos(id), " - ", pak.message, " - "));\r
280         \r
281         if(PreviewExists(pak.message))\r
282         {\r
283                 mv_preview[id] = true;\r
284                 //print("^2Found...\n");\r
285                 return;\r
286         } else {\r
287                 print("Requesting preview...\n");\r
288                 localcmd(strcat("\ncmd mv_getpic ", ftos(id), "\n"));\r
289         }\r
290 }\r
291 \r
292 void MapVote_CheckPK3(string pic, string pk3, float id)\r
293 {\r
294         entity pak;\r
295         pak = spawn();\r
296         pak.netname = pk3;\r
297         pak.message = pic;\r
298         pak.sv_entnum = id;\r
299         \r
300         pak.chain = mv_pk3list;\r
301         mv_pk3list = pak;\r
302         \r
303         if(pk3 != "")\r
304         {\r
305                 localcmd(strcat("\ncurl --pak ", pk3, "; wait; cl_cmd mv_download ", ftos(id), "\n"));\r
306         }\r
307         else\r
308         {\r
309                 Cmd_MapVote_MapDownload(tokenize_console(strcat("mv_download ", ftos(id))));\r
310         }\r
311 }\r
312 \r
313 void MapVote_CheckPic(string pic, string pk3, float id)\r
314 {\r
315         // never try to retrieve a pic for the "don't care" 'map'\r
316         if(mv_abstain && id == mv_num_maps - 1)\r
317                 return;\r
318 \r
319         if(PreviewExists(pic))\r
320         {\r
321                 mv_preview[id] = true;\r
322                 return;\r
323         }\r
324         MapVote_CheckPK3(pic, pk3, id);\r
325 }\r
326 \r
327 #define NUM_SSDIRS 4\r
328 string ssdirs[NUM_SSDIRS];\r
329 float n_ssdirs;\r
330 void MapVote_Init()\r
331 {\r
332         float i, j, power;\r
333         string map, pk3, s;\r
334 \r
335         precache_sound ("misc/invshot.wav");\r
336 \r
337         registercmd("+showscores");\r
338         registercmd("-showscores");\r
339 \r
340         mv_active = 1;\r
341 \r
342         mv_mousepos = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;\r
343         mv_selection = -1;\r
344 \r
345         for(n_ssdirs = 0; ; ++n_ssdirs)\r
346         {\r
347                 s = ReadString();\r
348                 if(s == "")\r
349                         break;\r
350                 if(n_ssdirs < NUM_SSDIRS)\r
351                         ssdirs[n_ssdirs] = s;\r
352         }\r
353         n_ssdirs = min(n_ssdirs, NUM_SSDIRS);\r
354 \r
355         mv_num_maps = min(MAPVOTE_COUNT, ReadByte());\r
356         mv_abstain = ReadByte();\r
357         if(mv_abstain)\r
358                 mv_abstain = 1; // must be 1 for bool-true, makes stuff easier\r
359         mv_detail = ReadByte();\r
360 \r
361         mv_ownvote = -1;\r
362         mv_timeout = ReadCoord();\r
363 \r
364         if(mv_num_maps <= 8)\r
365                 mv_maps_mask = ReadByte();\r
366         else\r
367                 mv_maps_mask = ReadShort();\r
368         \r
369         // Assume mv_pk3list is NULL, there should only be 1 mapvote per round\r
370         mv_pk3list = NULL; // I'm still paranoid!\r
371         \r
372         for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)\r
373         {\r
374                 mv_votes[i] = 0;\r
375 \r
376                 if(mv_maps_mask & power)\r
377                 {\r
378                         map = strzone(ReadString());\r
379                         pk3 = strzone(ReadString());\r
380                         j = bound(0, ReadByte(), n_ssdirs - 1);\r
381         \r
382                         mv_maps[i] = map;\r
383                         mv_pk3[i] = pk3;\r
384                         map = strzone(strcat(ssdirs[j], "/", map));\r
385                         mv_pics[i] = map;\r
386 \r
387                         mv_preview[i] = false;\r
388 \r
389                         //print(strcat("RECV: ", map, " in ", pk3, "\n"));\r
390                         MapVote_CheckPic(map, pk3, i);\r
391                 }\r
392                 else\r
393                 {\r
394                         mv_maps[i] = strzone("if-you-see-this-the-code-is-broken");\r
395                         mv_pk3[i] = strzone("if-you-see-this-the-code-is-broken");\r
396                         mv_pics[i] = strzone("if-you-see-this-the-code-is-broken");\r
397                         mv_preview[i] = false;\r
398                 }\r
399         }\r
400 \r
401         for(i = 0; i < n_ssdirs; ++i)\r
402                 ssdirs[n_ssdirs] = string_null;\r
403         n_ssdirs = 0;\r
404 }\r
405 \r
406 float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary)\r
407 {\r
408         float imp;\r
409 \r
410         if (!mv_active)\r
411                 return false;\r
412 \r
413         if (bInputType != 0)\r
414                 return false;\r
415 \r
416         if ('0' <= nPrimary && nPrimary <= '9')\r
417         {\r
418                 imp = nPrimary - '0';\r
419                 if (imp == 0) imp = 10;\r
420                 localcmd(strcat("\nimpulse ", ftos(imp), "\n"));\r
421                 return true;\r
422         }\r
423 \r
424         if (nPrimary == K_MOUSE1)\r
425                 if (mv_selection >= 0)\r
426                 {\r
427                         imp = min(mv_selection + 1, mv_num_maps);\r
428                         localcmd(strcat("\nimpulse ", ftos(imp), "\n"));\r
429                         return true;\r
430                 }\r
431 \r
432         return false;\r
433 }\r
434 \r
435 void MapVote_UpdateMask()\r
436 {\r
437         float i, power;\r
438         float oldmask;\r
439 \r
440         oldmask = mv_maps_mask;\r
441         if(mv_num_maps <= 8)\r
442                 mv_maps_mask = ReadByte();\r
443         else\r
444                 mv_maps_mask = ReadShort();\r
445 \r
446         if(oldmask & mv_maps_mask != oldmask)\r
447                 if(oldmask & mv_maps_mask == mv_maps_mask)\r
448                          sound(world, CHAN_AUTO, "misc_invshot.wav", VOL_BASE, ATTN_NONE);\r
449 \r
450         // remove votes that no longer apply\r
451         for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)\r
452                 if not(mv_maps_mask & power)\r
453                         mv_votes[i] = -1;\r
454 }\r
455 \r
456 void MapVote_UpdateVotes()\r
457 {\r
458         float i, power;\r
459         for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)\r
460         {\r
461                 if(mv_maps_mask & power)\r
462                 {\r
463                         if(mv_detail)\r
464                                 mv_votes[i] = ReadByte();\r
465                         else\r
466                                 mv_votes[i] = 0;\r
467                 }\r
468                 else\r
469                         mv_votes[i] = -1;\r
470         }\r
471 \r
472         mv_ownvote = ReadByte()-1;\r
473 }\r
474 \r
475 void Ent_MapVote()\r
476 {\r
477         float sf;\r
478 \r
479         sf = ReadByte();\r
480 \r
481         if(sf & 1)\r
482                 MapVote_Init();\r
483 \r
484         if(sf & 2)\r
485                 MapVote_UpdateMask();\r
486 \r
487         if(sf & 4)\r
488                 MapVote_UpdateVotes();\r
489 }\r
490 \r
491 void Net_MapVote_Picture()\r
492 {\r
493         float type;\r
494         type = ReadByte();\r
495         mv_preview[type] = true;\r
496         mv_pics[type] = strzone(ReadPicture());\r
497 }\r