]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/hud/panel/centerprint.qc
Removed centerprint zoom
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / centerprint.qc
1 #include "centerprint.qh"
2
3 #include "scoreboard.qh"
4 #include <common/notifications/all.qh>
5 #include <client/miscfunctions.qh>
6
7 // CenterPrint (#16)
8
9 void HUD_CenterPrint_Export(int fh)
10 {
11         // allow saving cvars that aesthetically change the panel into hud skin files
12         HUD_Write_Cvar("hud_panel_centerprint_align");
13         HUD_Write_Cvar("hud_panel_centerprint_flip");
14         HUD_Write_Cvar("hud_panel_centerprint_fontscale");
15         HUD_Write_Cvar("hud_panel_centerprint_fontscale_bold");
16         HUD_Write_Cvar("hud_panel_centerprint_time");
17         HUD_Write_Cvar("hud_panel_centerprint_fade_in");
18         HUD_Write_Cvar("hud_panel_centerprint_fade_out");
19         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent");
20         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passone");
21         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passone_minalpha");
22         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passtwo");
23         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passtwo_minalpha");
24         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_minfontsize");
25         HUD_Write_Cvar("hud_panel_centerprint_fade_minfontsize");
26 }
27
28 // These are the functions that draw the text at the center of the screen (e.g. frag messages and server MOTD).
29 // centerprint_Add parses a message and puts it in the circular buffer centerprint_messages
30 // centerprint_Add is usually called by Local_Notification_centerprint_Add, which is called
31 // by Local_Notification.
32 // HUD_CenterPrint draws all the messages on screen
33
34 const int CENTERPRINT_MAX_MSGS = 10;
35 const int CENTERPRINT_MAX_ENTRIES = 50;
36 const float CENTERPRINT_SPACING = 0.7;
37 int cpm_index;
38 string centerprint_messages[CENTERPRINT_MAX_MSGS];
39 int centerprint_msgID[CENTERPRINT_MAX_MSGS];
40 bool centerprint_bold[CENTERPRINT_MAX_MSGS];
41 float centerprint_time[CENTERPRINT_MAX_MSGS];
42 float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
43 int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
44 bool centerprint_showing;
45
46 float centerprint_medal_expire_time;
47 string centerprint_medal_icon;
48 float centerprint_medal_times;
49
50 bool centerprint_title_show;
51 string centerprint_title;
52
53 void centerprint_ClearTitle()
54 {
55         centerprint_title_show = false;
56 }
57 void centerprint_SetTitle(string title)
58 {
59         if(title != centerprint_title) {
60                 if(centerprint_title)
61                         strunzone(centerprint_title);
62                 centerprint_title = strzone(title);
63                 
64                 centerprint_title_show = true;
65         }
66 }
67
68 void centerprint_Medal(string icon, float times)
69 {
70         //LOG_INFOF("centerprint_Medal: icon: %s times: %d", icon, times);
71         //centerprint_medal_expire_time = time + autocvar_hud_panel_centerprint_time;
72         centerprint_medal_expire_time = time + MSG_MEDAL_TIME;
73         centerprint_medal_times = times;
74         if(centerprint_medal_icon)
75                 strunzone(centerprint_medal_icon);
76         centerprint_medal_icon = strzone(strcat("gfx/medal/", icon));
77         
78         centerprint_showing = true;
79 }
80
81 void centerprint_Add(int new_id, string strMessage, float duration, int countdown_num)
82 {
83         TC(int, new_id); TC(int, countdown_num);
84         //LOG_INFOF("centerprint_Add: ^2id: %d ^3dur: %d ^5countdown: %d\n'%s'", new_id, duration, countdown_num, strreplace("\n", "^7\\n^7", strMessage));
85         int i, j;
86
87         if(strMessage == "" && new_id == 0)
88                 return;
89
90         // strip BOLD_OPERATOR
91         bool is_bold = (substring(strMessage, 0, 5) == BOLD_OPERATOR);
92         if (is_bold)
93                 strMessage = substring(strMessage, 5, -1);
94
95         // strip trailing newlines
96         j = strlen(strMessage) - 1;
97         while(substring(strMessage, j, 1) == "\n" && j >= 0)
98                 --j;
99         if (j < strlen(strMessage) - 1)
100                 strMessage = substring(strMessage, 0, j + 1);
101
102         if(strMessage == "" && new_id == 0)
103                 return;
104
105         // strip leading newlines
106         j = 0;
107         while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
108                 ++j;
109         if (j > 0)
110                 strMessage = substring(strMessage, j, strlen(strMessage) - j);
111
112         if(strMessage == "" && new_id == 0)
113                 return;
114
115         if (!centerprint_showing)
116                 centerprint_showing = true;
117
118         for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
119         {
120                 if (j == CENTERPRINT_MAX_MSGS)
121                         j = 0;
122                 if (new_id && new_id == centerprint_msgID[j])
123                 {
124                         if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
125                         {
126                                 // fade out the current msg (duration and countdown_num are ignored)
127                                 centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
128                                 centerprint_expire_time[j] = -1; // don't use the variable time here!
129                                 return;
130                         }
131                         break; // found a msg with the same id, at position j
132                 }
133         }
134
135         if (i == CENTERPRINT_MAX_MSGS)
136         {
137                 // a msg with the same id was not found, add the msg at the next position
138                 --cpm_index;
139                 if (cpm_index == -1)
140                         cpm_index = CENTERPRINT_MAX_MSGS - 1;
141                 j = cpm_index;
142         }
143         strcpy(centerprint_messages[j], strMessage);
144         centerprint_bold[j] = is_bold;
145         centerprint_msgID[j] = new_id;
146         if (duration < 0)
147         {
148                 centerprint_time[j] = -1;
149                 centerprint_expire_time[j] = -1; // don't use the variable time here!
150         }
151         else
152         {
153                 if(duration == 0)
154                         duration = max(1, autocvar_hud_panel_centerprint_time);
155                 centerprint_time[j] = duration;
156                 centerprint_expire_time[j] = -1; // don't use the variable time here!
157         }
158         centerprint_countdown_num[j] = countdown_num;
159 }
160
161 void centerprint_Kill(int id)
162 {
163         TC(int, id);
164         centerprint_Add(id, "", 0, 0);
165 }
166
167 void centerprint_AddStandard(string strMessage)
168 {
169         centerprint_Add(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
170 }
171
172 void centerprint_KillAll()
173 {
174         for (int i=0; i<CENTERPRINT_MAX_MSGS; ++i)
175         {
176                 centerprint_expire_time[i] = 0;
177                 centerprint_time[i] = 1;
178                 centerprint_msgID[i] = 0;
179                 centerprint_bold[i] = false;
180                 strfree(centerprint_messages[i]);
181         }
182 }
183
184 float hud_configure_cp_generation_time;
185 void HUD_CenterPrint()
186 {
187         if(!autocvar__hud_configure)
188         {
189                 if(!autocvar_hud_panel_centerprint) return;
190
191                 if(hud_configure_prev)
192                         centerprint_KillAll();
193         }
194         else
195         {
196                 if(!hud_configure_prev)
197                 {
198                         centerprint_KillAll();
199                         hud_configure_cp_generation_time = time; // show a message immediately
200                 }
201                 if (time > hud_configure_cp_generation_time)
202                 {
203                         if(highlightedPanel == HUD_PANEL(CENTERPRINT))
204                         {
205                                 float r;
206                                 r = random();
207                                 if (r > 0.8)
208                                         centerprint_Add(floor(r*1000), sprintf(_("^3Countdown message at time %s, seconds left: ^COUNT"), seconds_tostring(time)), 1, 10);
209                                 else if (r > 0.55)
210                                         centerprint_Add(0, sprintf(_("^1Multiline message at time %s that\n^1lasts longer than normal"), seconds_tostring(time)), 20, 0);
211                                 else
212                                         centerprint_AddStandard(sprintf(_("Message at time %s"), seconds_tostring(time)));
213                                 hud_configure_cp_generation_time = time + 1 + random()*4;
214                         }
215                         else
216                         {
217                                 centerprint_Add(0, _("Generic message"), 10, 0);
218                                 hud_configure_cp_generation_time = time + 10 - random()*3;
219                         }
220                 }
221         }
222
223         HUD_Panel_LoadCvars();
224
225         if ( HUD_Radar_Clickable() )
226         {
227                 if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
228                         return;
229
230                 panel_pos.x = 0.5 * (vid_conwidth - panel_size.x);
231                 panel_pos.y = hud_panel_radar_bottom;
232                 panel_size.y = min(panel_size.y, vid_conheight - hud_panel_radar_bottom);
233         }
234         else if(!autocvar__hud_configure && scoreboard_fade_alpha)
235         {
236                 // move the panel below the scoreboard
237                 if (scoreboard_bottom >= 0.96 * vid_conheight)
238                         return;
239                 vector target_pos = vec2(0.5 * (vid_conwidth - panel_size.x), scoreboard_bottom);
240                 if(target_pos.y > panel_pos.y)
241                 {
242                         panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
243                         panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
244                 }
245         }
246
247         if (autocvar_hud_panel_centerprint_dynamichud)
248                 HUD_Scale_Enable();
249         else
250                 HUD_Scale_Disable();
251         HUD_Panel_DrawBg();
252
253         if (!centerprint_showing)
254                 return;
255
256         if(panel_bg_padding)
257         {
258                 panel_pos += '1 1 0' * panel_bg_padding;
259                 panel_size -= '2 2 0' * panel_bg_padding;
260         }
261
262         int entries;
263         float height;
264         vector fontsize;
265
266         int i, j, k, n, g;
267         float a, sz, align, current_msg_posY = 0, msg_size;
268         vector pos, mysize, newsize;
269         string ts;
270         bool all_messages_expired = true;
271
272         pos = panel_pos;
273         height = vid_conheight/50 * 4;
274         pos.y -= height;
275         
276         // z411 draw medals first
277         if (time < centerprint_medal_expire_time) {
278                 if(time < centerprint_medal_expire_time - MSG_MEDAL_FADE_TIME)
279                         a = 1;
280                 else
281                         a = (centerprint_medal_expire_time - time) / MSG_MEDAL_FADE_TIME;
282                 
283                 vector tmp_in = pos;
284                         
285                 mysize = draw_getimagesize(centerprint_medal_icon);
286                 newsize = vec2(height*(mysize.x/mysize.y), height);
287                 fontsize = '1 1 0' * (newsize.y/2);
288                 
289                 tmp_in.x += (panel_size.x - newsize.x) / 2; // center medal icon
290                 
291                 if(centerprint_medal_times < MSG_MEDAL_SCREEN) {
292                         tmp_in.x -= ((newsize.x * 1.1) * (centerprint_medal_times - 1) / 2);
293                         for(int t = 0; t < centerprint_medal_times; t++) {
294                                 drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
295                                 tmp_in.x += newsize.x * 1.1;
296                         }
297                 } else {
298                         drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
299                         tmp_in.x += newsize.x + fontsize.x * 0.25; // draw times next to it
300                         tmp_in.y += (newsize.y - fontsize.y) / 2;
301                         drawstring(tmp_in, ftos(centerprint_medal_times), fontsize, '1 1 1', a, DRAWFLAG_NORMAL);
302                 }
303                 
304                 all_messages_expired = false;
305         }
306         
307         // continue with normal procedure
308         pos.y += height;
309         
310         // z411 title
311         if(centerprint_title_show) {
312                 fontsize = '1 1 0' * vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale * 1.5;
313                 drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(centerprint_title, true, fontsize)), centerprint_title, fontsize, 1, DRAWFLAG_NORMAL);
314                 pos.y += fontsize.y + (fontsize.y / 4);
315                 
316                 all_messages_expired = false;
317         }
318         
319         // continue with normal procedure this time
320         
321         if (autocvar_hud_panel_centerprint_flip)
322                 pos.y += panel_size.y;
323         align = bound(0, autocvar_hud_panel_centerprint_align, 1);
324         for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
325         {
326                 bool is_bold = centerprint_bold[j];
327
328                 // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
329                 // height = panel_size_y/entries;
330                 // fontsize = '1 1 0' * height;
331                 height = (is_bold) ? vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale_bold : vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
332                 fontsize = '1 1 0' * height;
333                 entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
334
335                 if (j == CENTERPRINT_MAX_MSGS)
336                         j = 0;
337                 if (centerprint_expire_time[j] == -1)
338                 {
339                         // here we are sure the time variable is not altered by CSQC_Ent_Update
340                         centerprint_expire_time[j] = time;
341                         if (centerprint_time[j] > 0)
342                                 centerprint_expire_time[j] += centerprint_time[j];
343                 }
344                 if (centerprint_expire_time[j] <= time)
345                 {
346                         if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
347                         {
348                                 centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
349                                 if (centerprint_countdown_num[j] == 0)
350                                         continue;
351                                 centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
352                         }
353                         else if(centerprint_time[j] != -1)
354                                 continue;
355                 }
356
357                 all_messages_expired = false;
358
359                 // fade
360                 if(centerprint_time[j] < 0)  // Expired but forced. Expire time is the fade-in time.
361                         a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
362                 else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)  // Regularily printed. Not fading out yet.
363                         a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
364                 else // Expiring soon, so fade it out.
365                         a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
366
367                 if(centerprint_msgID[j] == ORDINAL(CPID_TIMEIN))
368                         a = 1;
369
370                 // while counting down show it anyway in order to hold the current message position
371                 if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0)  // Guaranteed invisible - don't show.
372                         continue;
373                 if (a > 1)
374                         a = 1;
375
376                 // set the size from fading in/out before subsequent fading
377                 //sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
378
379                 // also fade it based on positioning
380                 if(autocvar_hud_panel_centerprint_fade_subsequent)
381                 {
382                         // pass one: all messages after the first have half alpha
383                         a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1);
384                         // pass two: after that, gradually lower alpha even more for each message
385                         a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1);
386                 }
387                 a *= panel_fg_alpha;
388
389                 // finally set the size based on the new alpha from subsequent fading
390                 //sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
391                 sz = 1; // z411 disable ugly zoom shit
392                 drawfontscale = hud_scale * sz;
393
394                 if (centerprint_countdown_num[j])
395                         n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
396                 else
397                         n = tokenizebyseparator(centerprint_messages[j], "\n");
398
399                 if (autocvar_hud_panel_centerprint_flip)
400                 {
401                         // check if the message can be entirely shown
402                         for(k = 0; k < n; ++k)
403                         {
404                                 getWrappedLine_remaining = argv(k);
405                                 while(getWrappedLine_remaining)
406                                 {
407                                         ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
408                                         if (ts != "")
409                                                 pos.y -= fontsize.y;
410                                         else
411                                                 pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
412                                 }
413                         }
414                         current_msg_posY = pos.y; // save starting pos (first line) of the current message
415                 }
416
417                 msg_size = pos.y;
418                 for(k = 0; k < n; ++k)
419                 {
420                         getWrappedLine_remaining = argv(k);
421                         while(getWrappedLine_remaining)
422                         {
423                                 ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
424                                 if (ts != "")
425                                 {
426                                         if (align)
427                                                 pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize) * sz) * align;
428                                         if (a > 0.5/255.0)  // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
429                                                 if (is_bold) draw_beginBoldFont();
430                                                 drawcolorcodedstring(pos + eY * 0.5 * (1 - sz * hud_scale.x) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
431                                                 if (is_bold) draw_endBoldFont();
432                                         pos.y += fontsize.y;
433                                 }
434                                 else
435                                         pos.y += fontsize.y * CENTERPRINT_SPACING/2;
436                         }
437                 }
438
439                 ++g; // move next position number up
440
441                 msg_size = pos.y - msg_size;
442                 if (autocvar_hud_panel_centerprint_flip)
443                 {
444                         pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
445                         if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
446                                 pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
447
448                         if (pos.y < panel_pos.y) // check if the next message can be shown
449                         {
450                                 drawfontscale = hud_scale;
451                                 return;
452                         }
453                 }
454                 else
455                 {
456                         pos.y += CENTERPRINT_SPACING * fontsize.y;
457                         if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
458                                 pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
459
460                         if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
461                         {
462                                 drawfontscale = hud_scale;
463                                 return;
464                         }
465                 }
466         }
467
468         drawfontscale = hud_scale;
469         if (all_messages_expired)
470         {
471                 centerprint_showing = false;
472                 centerprint_KillAll();
473         }
474 }