Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
cl_mapvoting.qc
Go to the documentation of this file.
1#include "cl_mapvoting.qh"
2
3#include "net.qh"
4
5#include <client/draw.qh>
6#include <client/hud/_mod.qh>
8#include <common/util.qh>
9
10// MapVote (#21)
11
13{
14 // allow saving cvars that aesthetically change the panel into hud skin files
15 HUD_Write_Cvar("hud_panel_mapvote_highlight_border");
16}
17
18float xmin, xmax, ymin, ymax;
19
20const float MV_FADETIME = 0.2;
21
22bool PreviewExists(string name)
23{
25 return false;
26
27 if (fexists(strcat(name, ".tga"))
28 || fexists(strcat(name, ".png"))
29 || fexists(strcat(name, ".jpg"))
30 || fexists(strcat(name, ".pcx")))
31 return true;
32
33 return false;
34}
35
36string MapVote_FormatItem(int id, string text, int _count, float maxwidth, vector fontsize)
37{
38 TC(int, id);
39 string post = "";
40 if (mv_detail && (_count == 1 || (_count >= 0 && (mv_flags[id] & GTV_AVAILABLE))))
41 post = sprintf(_(" (%s)"), sprintf(count_votes(_count)));
42
43 string pre = strcat(itos(id + 1), ". ");
44 maxwidth -= stringwidth_nocolors(pre, fontsize) + stringwidth_nocolors(post, fontsize);
45 text = textShortenToWidth(text, maxwidth, fontsize, stringwidth_nocolors);
46 return strcat(pre, text, post);
47}
48
50{
51 TC(int, id);
52
53 if (!(mv_flags[id] & GTV_AVAILABLE))
54 return '1 1 1';
55 if (id == mv_ownvote)
56 return '0 1 0';
57 if (id == mv_selection)
58 return '1 1 0';
59
60 float time_frac = (time - mv_select_lasttime[id]) / MV_FADETIME;
61 return '1 1 0' + eZ * (time_frac >= 1 ? 1 : sqrt(time_frac));
62}
63
64void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype /* unused */, string pic, int _count, int id, int most_votes)
65{
66 TC(int, id);
67
68 // Find the correct alpha
69 float alpha;
70 if (!(mv_flags_start[id] & GTV_AVAILABLE))
71 alpha = 0.2; // The gametype isn't supported by the map
72 else if (!(mv_flags[id] & GTV_AVAILABLE) && mv_reduce_alpha)
73 alpha = mv_reduce_alpha; // Fade away if not one of the top 2 choice
74 else
75 alpha = 1; // Normal, full alpha
77
78 // Bounding box details
79 float rect_margin = hud_fontsize.y * 0.5;
80
83 maxh -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
84 tsize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
85
86 vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
87 vector rect_size = '1 1 0';
88 rect_size.x = tsize + rect_margin;
89 rect_size.y = maxh + rect_margin;
90
91 vector rgb = MapVote_RGB(id);
92 float time_frac;
93 if (id == mv_ownvote)
94 {
95 // Highlight current vote
96 time_frac = 0;
97 mv_select_lasttime[id] = time; // pretend it's selected, to also enlarge icon
98 drawfill(rect_pos, rect_size, rgb, 0.1 * alpha, DRAWFLAG_NORMAL);
100 }
101 else if (mv_flags[id] & GTV_AVAILABLE)
102 {
103 // Highlight selected item
104 if (id == mv_selection)
105 time_frac = 0;
106 else
107 time_frac = (time - mv_select_lasttime[id]) / MV_FADETIME;
108 if (time_frac < 1)
109 drawfill(rect_pos, rect_size, '1 1 1', 0.1 * (1 - sqrt(time_frac)) * panel_fg_alpha, DRAWFLAG_NORMAL);
110 }
111 else
112 time_frac = 1;
113
114 vector offset = pos;
115
116 float title_gap = gtv_text_size.y * 1.4; // distance between the title and the description
117 pos.y += title_gap;
118 maxh -= title_gap;
119
120 // Evaluate the image size
121 vector image_size = '3 3 0' * gtv_text_size.x;
122 if (maxh < image_size.y)
123 image_size = '1 1 0' * maxh;
124 image_size *= 0.8;
125 float desc_padding = gtv_text_size.x * 0.6;
126 pos.x += image_size.x + desc_padding;
127
128 // Split the description into lines, count lines
129 float desc_tsize = tsize - (image_size.x + desc_padding);
130 string the_label = mv_desc[id];
131 int nlines = 0;
132 if (the_label != "")
133 {
134 string ts;
135 int n = tokenizebyseparator(the_label, "\n");
136 for (int i = 0; i < n && maxh > (nlines + 1) * gtv_text_size_small.y; ++i)
137 {
139 while (getWrappedLine_remaining && maxh > (nlines + 1) * gtv_text_size_small.y)
140 if ((ts = getWrappedLine(desc_tsize, gtv_text_size_small, stringwidth_colors)) != "")
141 ++nlines;
142 }
143 }
144
145 // Center the contents in the bounding box
146 vector old_offset = offset;
147 float old_maxh = maxh;
148 maxh -= max(nlines * gtv_text_size_small.y, image_size.y);
149 if (maxh > 0)
150 offset.y += maxh * 0.5;
151
152 // Draw the title
153 bool is_bold = ((mv_flags[id] & GTV_AVAILABLE)
154 && (mv_tie_winner == id || (mv_tie_winner == -2 && _count == most_votes)));
155 if (is_bold)
157 string title = MapVote_FormatItem(id, mv_data[id], _count, tsize, gtv_text_size);
158 drawstring(offset, title, gtv_text_size, rgb, alpha, DRAWFLAG_NORMAL);
159 if (is_bold)
161
162 // Draw the icon
163 if (pic != "")
164 {
165 vector offset_padding;
166 if (time_frac >= 0 && time_frac < 1)
167 {
168 float extra_padding = min(desc_padding, title_gap);
169 float transition_progress = 1 - sqrt(time_frac);
170 image_size *= transition_progress * (extra_padding / image_size.x) + 1;
171 offset_padding = transition_progress * extra_padding * '-0.5 -0.5 0';
172 }
173 else
174 offset_padding = '0 0 0';
175 drawpic(eY * title_gap + eX * 0.5 * desc_padding + offset + offset_padding, pic, image_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
176 }
177
178 // Draw the description, line by line
179 if (the_label == "")
180 return;
181
182 string ts;
183 int n = tokenizebyseparator(the_label, "\n");
184 nlines = 0;
185 maxh = old_maxh;
186 offset -= old_offset;
187 for (int i = 0; i < n && maxh > (nlines + 1) * gtv_text_size_small.y; ++i)
188 {
190 while (getWrappedLine_remaining && maxh > (nlines + 1) * gtv_text_size_small.y)
191 if ((ts = getWrappedLine(desc_tsize, gtv_text_size_small, stringwidth_colors)) != "")
192 {
193 drawstring(pos + offset, ts, gtv_text_size_small, '1 1 1', alpha, DRAWFLAG_NORMAL);
194 pos.y += gtv_text_size_small.y;
195 ++nlines;
196 }
197 }
198}
199
200void MapVote_DrawMapPicture(string pic, vector pos, vector img_size, float theAlpha)
201{
202 if (pic == "")
203 drawfill(pos, img_size, '0.5 0.5 0.5', 0.7 * theAlpha, DRAWFLAG_NORMAL);
204 else
205 {
206 if (drawgetimagesize(pic) == '0 0 0')
207 drawpic(pos, draw_UseSkinFor("nopreview_map"), img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
208 else
209 drawpic(pos, pic, img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
210 }
211}
212
213void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, int _count, int id, int most_votes)
214{
215 TC(int, id);
216
217 float rect_margin = hud_fontsize.y * 0.5;
218 pos.x += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
219 pos.y += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
220 isize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
221 tsize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
222
223 vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
224 vector rect_size = '1 1 0';
225 rect_size.x = tsize + rect_margin;
226 rect_size.y = isize + rect_margin;
227
228 const float img_ar = 4/3;
229 vector img_size = '0 0 0';
230 img_size.x = min(tsize, isize * img_ar);
231 img_size.y = img_size.x / img_ar;
232 img_size.y -= hud_fontsize.y;
233 img_size.x = img_size.y * img_ar;
234
235 pos.y += (isize - img_size.y - hud_fontsize.y) * 0.5;
236
237 bool is_bold = ((mv_flags[id] & GTV_AVAILABLE)
238 && (mv_tie_winner == id || (mv_tie_winner == -2 && _count == most_votes)));
239 if (is_bold)
241 string label = MapVote_FormatItem(id, map, _count, tsize, hud_fontsize);
242 vector rgb = MapVote_RGB(id);
243
244 float text_size = stringwidth_nocolors(label, hud_fontsize);
245
246 float save_rect_sizex = rect_size.x;
247 rect_size.x = max(img_size.x, text_size) + rect_margin;
248 rect_pos.x += (save_rect_sizex - rect_size.x) * 0.5;
249
250 vector text_pos;
251 text_pos.x = pos.x + (tsize - text_size) * 0.5;
252 text_pos.y = pos.y + img_size.y;
253 text_pos.z = 0;
254
255 pos.x += (tsize - img_size.x) * 0.5;
256
257 float theAlpha = panel_fg_alpha;
258 if (!(mv_flags[id] & GTV_AVAILABLE) && mv_reduce_alpha)
259 theAlpha *= mv_reduce_alpha;
260 else if (mv_winner && mv_winner_alpha)
261 theAlpha *= mv_winner_alpha;
262
263 if (!mv_winner)
264 {
265 if (id == mv_ownvote)
266 {
267 // Highlight current vote
268 drawfill(rect_pos, rect_size, rgb, 0.1 * theAlpha, DRAWFLAG_NORMAL);
270 }
271 else if (mv_flags[id] & GTV_AVAILABLE)
272 {
273 // Highlight selected item
274 float time_frac;
275 if (id == mv_selection)
276 time_frac = 0;
277 else
278 time_frac = (time - mv_select_lasttime[id]) / MV_FADETIME;
279 if (time_frac < 1)
280 drawfill(rect_pos, rect_size, '1 1 1', 0.1 * (1 - sqrt(time_frac)) * panel_fg_alpha, DRAWFLAG_NORMAL);
281 }
282 }
283
284 MapVote_DrawMapPicture(pic, pos, img_size, theAlpha);
285
286 drawstring(text_pos, label, hud_fontsize, rgb, theAlpha, DRAWFLAG_NORMAL);
287 if (is_bold)
289}
290
291void MapVote_DrawAbstain(vector pos, float tsize, int _count, int id)
292{
293 string label = MapVote_FormatItem(id, _("Don't care"), _count, tsize, hud_fontsize);
294
295 float theAlpha = (mv_winner && mv_winner_alpha)
297 : 1;
298 theAlpha *= panel_fg_alpha;
299 pos.x -= 0.5 * stringwidth(label, false, hud_fontsize);
300 drawstring(pos, label, hud_fontsize, MapVote_RGB(id), theAlpha, DRAWFLAG_NORMAL);
301}
302
304{
305 int id = (mv_winner ? mv_winner - 1 : mv_selection);
306
307 float theAlpha = 0;
308 if (id != -1 && (mv_flags[id] & GTV_AVAILABLE)) // if the map is valid, update cache and time
309 {
310 if (mv_suggester_cache == "" && mv_suggester[id] == "")
311 return;
312 if (mv_suggester[id] != "") // update cache to current, set time
313 {
316 theAlpha = 1;
317 }
318 }
319 if (mv_suggester_cache != "" && theAlpha != 1) // figure out alpha for cache if it's partly-faded
320 {
321 float time_frac = (time - mv_suggester_cachetime) / MV_FADETIME;
322 if (time_frac >= 1) // finished fading out, delete cache
323 {
325 return;
326 }
327 theAlpha = 1 - sqrt(time_frac);
328 }
329 if (!theAlpha)
330 return;
331
332 string label = sprintf(_("Suggested by: %s"), ColorTranslateRGB(mv_suggester_cache));
333
334 theAlpha *= panel_fg_alpha;
335 pos.x -= 0.5 * stringwidth(label, true, hud_fontsize);
336 drawcolorcodedstring(pos, label, hud_fontsize, theAlpha, DRAWFLAG_NORMAL);
337}
338
339vector MapVote_GridVec(vector gridspec, int i, int m)
340{
341 TC(int, i); TC(int, m);
342 int r = i % m;
343 return
344 eX * (gridspec.x * r)
345 +
346 eY * (gridspec.y * (i - r) / m);
347}
348
349int MapVote_Selection(vector topleft, vector cellsize, int rows, int columns)
350{
351 if (mv_winner)
352 return -1;
353
355
356 for (int c, r = 0; r < rows; ++r)
357 for (c = 0; c < columns; ++c)
358 if (mousepos.x >= topleft.x + cellsize.x * c
359 && mousepos.x <= topleft.x + cellsize.x * (c + 1)
360 && mousepos.y >= topleft.y + cellsize.y * r
361 && mousepos.y <= topleft.y + cellsize.y * (r + 1))
362 {
363 mv_mouse_selection = r * columns + c;
364 break;
365 }
366
371
373 return mv_selection;
374 return mv_mouse_selection;
375}
376
378void MapVote_Draw(bool should_draw)
379{
380 if (!should_draw)
381 return;
382 //if (intermission != 2) return;
383 if (!mv_active)
384 return;
385
387
388 float center = (vid_conwidth - 1) * 0.5;
389 xmin = vid_conwidth * (gametypevote ? 0.08 : 0.1);
391 ymin = 20;
393
394 if (chat_posy + chat_sizey * 0.5 < vid_conheight * 0.5)
395 ymin += chat_sizey;
396 else
397 ymax -= chat_sizey;
398
399 hud_fontsize = HUD_GetFontsize("hud_fontsize");
400 if (gametypevote)
401 {
404 }
405
406 vector pos;
407 pos.y = ymin;
408 pos.z = 0;
409
412
413 string map = (gametypevote) ? _("Decide the gametype") : _("Vote for a map");
414 if (!mv_winner)
415 {
416 pos.x = center - stringwidth(map, false, hud_fontsize * 2) * 0.5;
417 drawstring(pos, map, hud_fontsize * 2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
418 }
419 pos.y += hud_fontsize.y * 2;
420
421 if (mv_chosenmap != "")
422 {
423 pos.y += hud_fontsize.y * 0.25;
424 pos.x = center - stringwidth(mv_chosenmap, false, hud_fontsize * 1.5) * 0.5;
426 pos.y += hud_fontsize.y * 1.5;
427 }
428 pos.y += hud_fontsize.y * 0.5;
429
431
432 int i;
433 if (mv_winner)
434 map = mv_entries[mv_winner - 1];
435 else
436 {
437 i = ceil(max(1, mv_timeout - time)); // make sure 0 seconds left never shows up, not even for a frame
438 map = count_seconds(i);
439 }
440 pos.x = center - stringwidth(map, false, hud_fontsize * 1.5) * 0.5;
441 drawstring(pos, map, hud_fontsize * 1.5, '0 1 0', panel_fg_alpha, DRAWFLAG_NORMAL);
442 pos.y += hud_fontsize.y * 1.5;
443 pos.y += hud_fontsize.y * 0.5;
444
445 // base for multi-column stuff...
446 pos.y += hud_fontsize.y;
447 pos.x = xmin;
448 ymin = pos.y;
449 float abstain_spacing = panel_bg_border + hud_fontsize.y;
450 float suggester_spacing = hud_fontsize.y * 1.5;
451 if (mv_abstain)
452 ymax -= abstain_spacing;
453 bool were_suggesters = (mv_suggester[0] != ""); // suggestions are placed at the start
454 if (were_suggesters)
455 ymax -= suggester_spacing;
456
457 // higher than the image itself ratio for mapvote items to reserve space for long map names
458 float item_aspect = (gametypevote) ? 3/1 : 5/3;
459 vector table_size = HUD_GetTableSize_BestItemAR(mv_count_real, vec2(xmax - xmin, ymax - ymin), item_aspect);
460 mv_columns = table_size.x;
461 int rows = table_size.y;
462
463 vector dist = vec2((xmax - xmin) / mv_columns, (ymax - pos.y) / rows);
464
465 // reduce size of too wide items
466 float tmp = vid_conwidth / 3; // max width
467 if (dist.x > tmp)
468 {
469 dist.x = tmp;
470 dist.y = min(dist.y, dist.x / item_aspect);
471 }
472 tmp = vid_conheight / 3; // max height
473 if (dist.y > tmp)
474 {
475 dist.y = tmp;
476 dist.x = min(dist.x, dist.y * item_aspect);
477 }
478
479 // reduce size to fix aspect ratio
480 if (dist.x / dist.y > item_aspect)
481 dist.x = dist.y * item_aspect;
482 else
483 dist.y = dist.x / item_aspect;
484
485 // adjust table pos and size according to the new size
486 float offset = ((xmax - pos.x) - dist.x * mv_columns) * 0.5;
487 xmin = pos.x += offset;
488 xmax -= offset;
489 offset = ((ymax - pos.y) - dist.y * rows) * 0.5;
490 ymax -= 2 * offset;
491
492 // override panel_pos and panel_size
493 panel_pos.x = pos.x;
494 panel_pos.y = pos.y;
495 panel_size.x = xmax - xmin;
496 panel_size.y = ymax - ymin;
498
500 {
501 // FIXME item AR gets slightly changed here...
502 // it's rather hard to avoid it at this point
503 dist.x -= 2 * panel_bg_padding / mv_columns;
504 dist.y -= 2 * panel_bg_padding / rows;
505 xmin = pos.x += panel_bg_padding;
506 ymin = pos.y += panel_bg_padding;
507 xmax -= 2 * panel_bg_padding;
508 ymax -= 2 * panel_bg_padding;
509 }
510
511 mv_selection = MapVote_Selection(pos, dist, rows, mv_columns);
512 if (mv_selection != -1)
514
515 if (mv_reduce_time)
516 mv_reduce_alpha = max(0.2, 1 - (time - mv_reduce_time) ** 2);
517
518 if (mv_winner_time)
519 mv_winner_alpha = max(0.2, 1 - sqrt(max(0, time - mv_winner_time)));
520
521 int most_votes = -1;
522 if (mv_tie_winner == -2)
523 for (i = 0; i < mv_count_real; ++i)
524 if (mv_votes[i] > most_votes)
525 most_votes = mv_votes[i];
526
527 void(vector, float, float, string, string, float, int, int) DrawItem;
528 if (gametypevote)
530 else
531 DrawItem = MapVote_DrawMapItem;
532
533 for (i = 0; i < mv_count_real; ++i)
534 {
535 tmp = mv_votes[i]; // FTEQCC bug: too many array accesses in the function call screw it up
536 map = mv_entries[i];
537 string pic = (mv_preview[i] ? mv_pics[i] : "");
538 DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), dist.y, dist.x, map, pic, tmp, i, most_votes);
539 }
540
541 pos.y = ymax + abstain_spacing;
542 if (mv_abstain)
543 {
544 tmp = mv_votes[i];
545 pos.x = center;
546 MapVote_DrawAbstain(pos, xmax - xmin, tmp, i);
547 pos.y += suggester_spacing;
548 }
549
550 if (mv_winner)
551 {
552 // expand winner map image
553 vector startsize;
554 startsize.z = 0;
555 startsize.y = vid_conheight * 0.1;
556 startsize.x = startsize.y * 4/3;
557 vector startpos = panel_pos + (panel_size - startsize) * 0.5;
558
559 vector endsize;
560 endsize.z = 0;
561 endsize.y = vid_conheight * 0.5;
562 endsize.x = endsize.y * 4/3;
563 vector endpos;
564 endpos.z = 0;
565 endpos.y = panel_pos.y;
566 endpos.x = (vid_conwidth - endsize.x) * 0.5;
567
568 float f = bound(0, sqrt((time - mv_winner_time) * 2), 1);
569 float theAlpha = f;
570 f = min(0.1 + f, 1);
571 vector img_size = endsize * f + startsize * (1 - f);
572 vector img_pos = endpos * f + startpos * (1 - f);
573
574 MapVote_DrawMapPicture(mv_pics[mv_winner - 1], img_pos, img_size, theAlpha);
575
576 if (were_suggesters)
577 {
578 float suggester_startposy = pos.y;
579 float suggester_endposy = panel_pos.y + endsize.y + hud_fontsize.y;
580 pos.y = suggester_endposy * f + suggester_startposy * (1 - f);
581 }
582 }
583
584 if (were_suggesters)
585 {
586 pos.x = center;
588 }
589}
590
592{
593 TC(int, argc);
594
595 if (argc != 2 || !mv_pk3list)
596 {
597 LOG_INFO(_("mv_mapdownload: ^3You're not supposed to use this command on your own!"));
598 return;
599 }
600
601 entity pak;
602 int id = stoi(argv(1));
603 for (pak = mv_pk3list; pak; pak = pak.chain)
604 if (pak.sv_entnum == id)
605 break;
606
607 if (!pak || pak.sv_entnum != id)
608 {
609 LOG_INFO(_("^1Error:^7 Couldn't find pak index."));
610 return;
611 }
612
613 if (PreviewExists(pak.message))
614 {
615 mv_preview[id] = true;
616 return;
617 }
618 else
619 {
620 LOG_INFO(_("Requesting preview..."));
621 localcmd("\ncmd mv_getpicture ", ftos(id), "\n");
622 }
623}
624
625void MapVote_CheckPK3(string pic, string pk3, int id)
626{
627 TC(int, id);
628 entity pak = spawn();
629 pak.message = pic;
630 pak.netname = pk3;
631 pak.sv_entnum = id;
632
633 pak.chain = mv_pk3list;
634 mv_pk3list = pak;
635
636 if (pk3 != "")
637 localcmd("\ncurl --pak ", pk3, "; wait; cl_cmd mv_download ", itos(id), "\n");
638 else
640}
641
642void MapVote_CheckPic(string pic, string pk3, int id)
643{
644 TC(int, id);
645 // never try to retrieve a pic for the "don't care" 'map'
646 if (mv_abstain && id == mv_count - 1)
647 return;
648
649 if (PreviewExists(pic))
650 {
651 mv_preview[id] = true;
652 return;
653 }
654 MapVote_CheckPK3(pic, pk3, id);
655}
656
658{
659 TC(int, pos);
660 int imp;
661 if (pos < 0)
662 imp = mv_count - 1;
663 else
664 imp = pos < 1 ? mv_count - 1 : pos - 1;
665 if (!(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote)
667 return imp;
668}
670{
671 TC(int, pos);
672 int imp;
673 if (pos < 0)
674 imp = 0;
675 else
676 imp = pos >= mv_count - 1 ? 0 : pos + 1;
677 if (!(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote)
679 return imp;
680}
681int MapVote_MoveUp(int pos)
682{
683 TC(int, pos);
684 int imp;
685 if (pos < 0)
686 imp = mv_count - 1;
687 else
688 {
689 imp = pos - mv_columns;
690 if (imp < 0)
691 {
692 int mv_rows = ceil(mv_count / mv_columns);
693 if (imp == -mv_columns) // pos == 0
694 imp = mv_columns * mv_rows - 1;
695 else
696 imp += mv_columns * mv_rows - 1;
697 }
698 }
699 if (!(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote)
701 return imp;
702}
704{
705 TC(int, pos);
706 int imp;
707 if (pos < 0)
708 imp = 0;
709 else
710 {
711 imp = pos + mv_columns;
712 if (imp >= mv_count)
713 {
714 int col = imp % mv_columns;
715 if (col == mv_columns - 1)
716 imp = 0;
717 else
718 imp = col + 1;
719 }
720 }
721 if (!(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote)
723 return imp;
724}
725
726float MapVote_InputEvent(int bInputType, float nPrimary, float nSecondary)
727{
728 TC(int, bInputType);
729
730 static int first_digit = 0;
731 if (!mv_active || isdemo())
732 return false;
733
734 if (bInputType == 3)
735 {
736 mousepos.x = nPrimary;
737 mousepos.y = nSecondary;
738 mv_selection_keyboard = false;
739 return true;
740 }
741
742 if (bInputType == 2)
743 {
744 mv_selection_keyboard = false;
745 return false;
746 }
747
748 // at this point bInputType can only be 0 or 1 (key pressed or released)
749 bool key_pressed = (bInputType == 0);
750
751 if (key_pressed)
752 {
753 if (nPrimary == K_ALT) hudShiftState |= S_ALT;
754 if (nPrimary == K_CTRL) hudShiftState |= S_CTRL;
755 if (nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
756 }
757 else
758 {
759 if (nPrimary == K_ALT) hudShiftState &= ~S_ALT;
760 if (nPrimary == K_CTRL) hudShiftState &= ~S_CTRL;
761 if (nPrimary == K_SHIFT) hudShiftState &= ~S_SHIFT;
762
763 if (nPrimary == K_CTRL)
764 first_digit = 0;
765 }
766
767 /* Key release events must be handled by the engine otherwise the on-press command such as +jump
768 * executed by pressing SPACE before entering the map voting screen won't be followed by the
769 * on-release command (-jump) on key release once entered the map voting screen, causing +jump
770 * to stay active even on the next map and automatically forcing the player to join
771 */
772 if (!key_pressed)
773 return false;
774
775 int imp = 0;
776 switch (nPrimary)
777 {
778 #define IMPULSE_ARROW_CASE(key, func) \
779 case key: \
780 if (!mv_winner) \
781 { \
782 mv_selection_keyboard = true; \
783 mv_selection = func(mv_selection); \
784 } \
785 return true
790 #undef IMPULSE_ARROW_CASE
791 case K_KP_ENTER:
792 case K_ENTER:
793 case K_SPACE:
796 return true;
797 #define IMPULSE_NUM_CASE(num, imp_num) \
798 case '0' + num: \
799 case K_KP_##num: \
800 imp = imp_num; \
801 break
802 IMPULSE_NUM_CASE(1, 1);
803 IMPULSE_NUM_CASE(2, 2);
804 IMPULSE_NUM_CASE(3, 3);
805 IMPULSE_NUM_CASE(4, 4);
806 IMPULSE_NUM_CASE(5, 5);
807 IMPULSE_NUM_CASE(6, 6);
808 IMPULSE_NUM_CASE(7, 7);
809 IMPULSE_NUM_CASE(8, 8);
810 IMPULSE_NUM_CASE(9, 9);
811 IMPULSE_NUM_CASE(0, 10);
812 #undef IMPULSE_NUM_CASE
813 }
814
815 if (imp && hudShiftState & S_CTRL)
816 {
817 if (!first_digit)
818 {
819 first_digit = imp % 10;
820 return true;
821 }
822 else
823 imp = first_digit * 10 + (imp % 10);
824 }
825
826 if (nPrimary == K_MOUSE1)
827 {
828 mv_selection_keyboard = false;
830 if (mv_selection >= 0)
832 }
833
834 if (nPrimary == K_MOUSE2)
835 return true; // do nothing
836
837 if (imp)
838 {
839 if (!mv_winner && imp <= mv_count)
841 return true;
842 }
843
844 return false;
845}
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float xmin
void Cmd_MapVote_MapDownload(int argc)
void MapVote_Draw_Export(int fh)
void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype, string pic, int _count, int id, int most_votes)
void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, int _count, int id, int most_votes)
int MapVote_MoveRight(int pos)
vector MapVote_GridVec(vector gridspec, int i, int m)
void MapVote_CheckPic(string pic, string pk3, int id)
void MapVote_DrawMapPicture(string pic, vector pos, vector img_size, float theAlpha)
float ymin
void MapVote_CheckPK3(string pic, string pk3, int id)
#define IMPULSE_ARROW_CASE(key, func)
bool PreviewExists(string name)
int MapVote_Selection(vector topleft, vector cellsize, int rows, int columns)
string MapVote_FormatItem(int id, string text, int _count, float maxwidth, vector fontsize)
int MapVote_MoveLeft(int pos)
float xmax
float MapVote_InputEvent(int bInputType, float nPrimary, float nSecondary)
vector MapVote_RGB(int id)
void MapVote_DrawSuggester(vector pos)
int MapVote_MoveUp(int pos)
void MapVote_DrawAbstain(vector pos, float tsize, int _count, int id)
#define IMPULSE_NUM_CASE(num, imp_num)
float ymax
int MapVote_MoveDown(int pos)
const float MV_FADETIME
void MapVote_Draw(bool should_draw)
Draws map vote or gametype vote.
int mv_columns
bool mv_selection_keyboard
int mv_tie_winner
int mv_selection
float mv_select_lasttime[MAPVOTE_COUNT]
vector gtv_text_size_small
int mv_flags_start[MAPVOTE_COUNT]
(gt) mv_flags initially
bool autocvar_cl_readpicture_force
int mv_mouse_selection
float mv_winner_time
float mv_reduce_alpha
string mv_chosenmap
bool mv_active
float mv_suggester_cachetime
string mv_suggester_cache
string mv_desc[MAPVOTE_COUNT]
(gt) gametype description
entity mv_pk3list
vector gtv_text_size
int mv_ownvote
string mv_data[MAPVOTE_COUNT]
(shared) map pk3 name/gametype human readable name
bool gametypevote
float autocvar_hud_panel_mapvote_highlight_border
float mv_winner_alpha
float mv_preview[MAPVOTE_COUNT]
(shared) whether there is a pic
string mv_pics[MAPVOTE_COUNT]
(shared) pic file location
void drawborderlines(float thickness, vector pos, vector dim, vector color, float theAlpha, float drawflag)
Definition draw.qc:5
#define drawcolorcodedstring(position, text, scale, alpha, flag)
Definition draw.qh:30
#define drawstring(position, text, scale, rgb, alpha, flag)
Definition draw.qh:27
#define drawpic(position, pic, size, rgb, alpha, flag)
Definition draw.qh:21
#define draw_beginBoldFont()
Definition draw.qh:4
#define drawfill(position, size, rgb, alpha, flag)
Definition draw.qh:36
#define draw_endBoldFont()
Definition draw.qh:5
float alpha
Definition items.qc:13
vector hud_fontsize
Definition main.qh:77
string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition util.qc:1173
string getWrappedLine(float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition util.qc:1133
string getWrappedLine_remaining
Definition util.qh:154
#define count_votes(num)
Definition counting.qh:42
#define count_seconds(time)
Definition counting.qh:122
const float DRAWFLAG_NORMAL
vector drawgetimagesize(string pic)
float time
#define stringwidth
#define spawn
#define tokenize_console
#define tokenizebyseparator
ERASEABLE bool fexists(string f)
Definition file.qh:4
void HUD_Panel_LoadCvars()
Definition hud.qc:215
vector HUD_GetFontsize(string cvarname)
Definition hud.qc:112
vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
Definition hud.qc:172
void HUD_Scale_Disable()
Definition hud.qc:84
vector panel_size
Definition hud.qh:163
float panel_fg_alpha
Definition hud.qh:169
const int S_SHIFT
Definition hud.qh:129
int hudShiftState
Definition hud.qh:128
const int S_ALT
Definition hud.qh:131
float panel_bg_padding
Definition hud.qh:174
float panel_bg_border
Definition hud.qh:172
float chat_sizey
Definition hud.qh:183
#define HUD_Panel_DrawBg()
Definition hud.qh:55
vector panel_pos
Definition hud.qh:162
float chat_posy
Definition hud.qh:182
vector mousepos
Definition hud.qh:103
const int S_CTRL
Definition hud.qh:130
#define HUD_Write_Cvar(cvar)
Definition hud_config.qh:40
#define stoi(s)
Definition int.qh:4
#define itos(i)
Definition int.qh:6
float K_SHIFT
Definition keycodes.qc:22
float K_UPARROW
Definition keycodes.qc:15
float K_DOWNARROW
Definition keycodes.qc:16
float K_MOUSE1
Definition keycodes.qc:129
float K_CTRL
Definition keycodes.qc:21
float K_RIGHTARROW
Definition keycodes.qc:18
float K_SPACE
Definition keycodes.qc:10
float K_ALT
Definition keycodes.qc:20
float K_ENTER
Definition keycodes.qc:8
float K_LEFTARROW
Definition keycodes.qc:17
float K_MOUSE2
Definition keycodes.qc:130
float K_KP_ENTER
Definition keycodes.qc:74
#define TC(T, sym)
Definition _all.inc:82
noref float vid_conwidth
Definition draw.qh:7
noref float vid_conheight
Definition draw.qh:8
#define LOG_INFO(...)
Definition log.qh:62
void MapVote_WritePlayerVote(int index)
Definition net.qc:43
bool mv_abstain
(shared) if abstaining is possible, false in gametype voting
Definition mapvoting.qh:21
int mv_count
(shared) number of maps/gametypes
Definition mapvoting.qh:14
int mv_flags[MAPVOTE_COUNT]
(shared) map/gametype flags
Definition mapvoting.qh:18
string mv_entries[MAPVOTE_COUNT]
(shared) map name or gametype name
Definition mapvoting.qh:16
int mv_detail
(shared) how much information about the votes/results is revealed
Definition mapvoting.qh:20
float mv_reduce_time
Definition mapvoting.qh:22
int mv_winner
Definition mapvoting.qh:24
int mv_count_real
(shared) number of maps/gametypes, excluding abstain
Definition mapvoting.qh:15
const int GTV_AVAILABLE
Can be voted.
Definition mapvoting.qh:28
int mv_votes[MAPVOTE_COUNT]
(shared) number of votes for the map/gametype
Definition mapvoting.qh:19
string mv_suggester[MAPVOTE_COUNT]
(maps) .netname of the player who suggested the map
Definition mapvoting.qh:17
float mv_timeout
Definition mapvoting.qh:23
string name
Definition menu.qh:30
void localcmd(string command,...)
float isdemo()
float ceil(float f)
float bound(float min, float value, float max)
float sqrt(float f)
float min(float f,...)
string ftos(float f)
string argv(float n)
float max(float f,...)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
vector
Definition self.qh:96
void
Definition self.qh:76
int int int imp
Definition impulse.qc:90
ERASEABLE string ColorTranslateRGB(string s)
Definition string.qh:194
float stringwidth_nocolors(string s, vector theSize)
Definition string.qh:35
float stringwidth_colors(string s, vector theSize)
Definition string.qh:30
const vector eY
Definition vector.qh:44
const vector eZ
Definition vector.qh:45
const vector eX
Definition vector.qh:43
#define vec2(...)
Definition vector.qh:95