1 #include "centerprint.qh"
3 #include "scoreboard.qh"
4 #include <common/notifications/all.qh>
5 #include <client/miscfunctions.qh>
9 void HUD_CenterPrint_Export(int fh)
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");
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
34 const int CENTERPRINT_MAX_MSGS = 10;
35 const int CENTERPRINT_MAX_ENTRIES = 50;
36 const float CENTERPRINT_SPACING = 0.7;
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;
46 float centerprint_medal_expire_time;
47 string centerprint_medal_icon;
48 float centerprint_medal_times;
50 bool centerprint_title_show;
51 string centerprint_title;
53 void centerprint_ClearTitle()
55 centerprint_title_show = false;
57 void centerprint_SetTitle(string title)
59 if(title != centerprint_title) {
61 strunzone(centerprint_title);
62 centerprint_title = strzone(title);
64 centerprint_title_show = true;
68 void centerprint_Medal(string icon, float times)
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));
78 centerprint_showing = true;
81 void centerprint_Add(int new_id, string strMessage, float duration, int countdown_num)
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));
87 if(strMessage == "" && new_id == 0)
90 // strip BOLD_OPERATOR
91 bool is_bold = (substring(strMessage, 0, 5) == BOLD_OPERATOR);
93 strMessage = substring(strMessage, 5, -1);
95 // strip trailing newlines
96 j = strlen(strMessage) - 1;
97 while(substring(strMessage, j, 1) == "\n" && j >= 0)
99 if (j < strlen(strMessage) - 1)
100 strMessage = substring(strMessage, 0, j + 1);
102 if(strMessage == "" && new_id == 0)
105 // strip leading newlines
107 while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
110 strMessage = substring(strMessage, j, strlen(strMessage) - j);
112 if(strMessage == "" && new_id == 0)
115 if (!centerprint_showing)
116 centerprint_showing = true;
118 for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
120 if (j == CENTERPRINT_MAX_MSGS)
122 if (new_id && new_id == centerprint_msgID[j])
124 if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
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!
131 break; // found a msg with the same id, at position j
135 if (i == CENTERPRINT_MAX_MSGS)
137 // a msg with the same id was not found, add the msg at the next position
140 cpm_index = CENTERPRINT_MAX_MSGS - 1;
143 strcpy(centerprint_messages[j], strMessage);
144 centerprint_bold[j] = is_bold;
145 centerprint_msgID[j] = new_id;
148 centerprint_time[j] = -1;
149 centerprint_expire_time[j] = -1; // don't use the variable time here!
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!
158 centerprint_countdown_num[j] = countdown_num;
161 void centerprint_Kill(int id)
164 centerprint_Add(id, "", 0, 0);
167 void centerprint_AddStandard(string strMessage)
169 centerprint_Add(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
172 void centerprint_KillAll()
174 for (int i=0; i<CENTERPRINT_MAX_MSGS; ++i)
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]);
184 float hud_configure_cp_generation_time;
185 void HUD_CenterPrint()
187 if(!autocvar__hud_configure)
189 if(!autocvar_hud_panel_centerprint) return;
191 if(hud_configure_prev)
192 centerprint_KillAll();
196 if(!hud_configure_prev)
198 centerprint_KillAll();
199 hud_configure_cp_generation_time = time; // show a message immediately
201 if (time > hud_configure_cp_generation_time)
203 if(highlightedPanel == HUD_PANEL(CENTERPRINT))
208 centerprint_Add(floor(r*1000), sprintf(_("^3Countdown message at time %s, seconds left: ^COUNT"), seconds_tostring(time)), 1, 10);
210 centerprint_Add(0, sprintf(_("^1Multiline message at time %s that\n^1lasts longer than normal"), seconds_tostring(time)), 20, 0);
212 centerprint_AddStandard(sprintf(_("Message at time %s"), seconds_tostring(time)));
213 hud_configure_cp_generation_time = time + 1 + random()*4;
217 centerprint_Add(0, _("Generic message"), 10, 0);
218 hud_configure_cp_generation_time = time + 10 - random()*3;
223 HUD_Panel_LoadCvars();
225 if ( HUD_Radar_Clickable() )
227 if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
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);
234 else if(!autocvar__hud_configure && scoreboard_fade_alpha)
236 // move the panel below the scoreboard
237 if (scoreboard_bottom >= 0.96 * vid_conheight)
239 vector target_pos = vec2(0.5 * (vid_conwidth - panel_size.x), scoreboard_bottom);
240 if(target_pos.y > panel_pos.y)
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);
247 if (autocvar_hud_panel_centerprint_dynamichud)
253 if (!centerprint_showing)
258 panel_pos += '1 1 0' * panel_bg_padding;
259 panel_size -= '2 2 0' * panel_bg_padding;
267 float a, sz, align, current_msg_posY = 0, msg_size;
268 vector pos, mysize, newsize;
270 bool all_messages_expired = true;
273 height = vid_conheight/50 * 4;
276 // z411 draw medals first
277 if (time < centerprint_medal_expire_time) {
278 if(time < centerprint_medal_expire_time - MSG_MEDAL_FADE_TIME)
281 a = (centerprint_medal_expire_time - time) / MSG_MEDAL_FADE_TIME;
285 mysize = draw_getimagesize(centerprint_medal_icon);
286 newsize = vec2(height*(mysize.x/mysize.y), height);
287 fontsize = '1 1 0' * (newsize.y/2);
289 tmp_in.x += (panel_size.x - newsize.x) / 2; // center medal icon
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;
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);
304 all_messages_expired = false;
307 // continue with normal procedure
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);
316 all_messages_expired = false;
319 // continue with normal procedure this time
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)
326 bool is_bold = centerprint_bold[j];
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);
335 if (j == CENTERPRINT_MAX_MSGS)
337 if (centerprint_expire_time[j] == -1)
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];
344 if (centerprint_expire_time[j] <= time)
346 if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
348 centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
349 if (centerprint_countdown_num[j] == 0)
351 centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
353 else if(centerprint_time[j] != -1)
357 all_messages_expired = false;
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);
367 if(centerprint_msgID[j] == ORDINAL(CPID_TIMEIN))
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.
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);
379 // also fade it based on positioning
380 if(autocvar_hud_panel_centerprint_fade_subsequent)
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);
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;
394 if (centerprint_countdown_num[j])
395 n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
397 n = tokenizebyseparator(centerprint_messages[j], "\n");
399 if (autocvar_hud_panel_centerprint_flip)
401 // check if the message can be entirely shown
402 for(k = 0; k < n; ++k)
404 getWrappedLine_remaining = argv(k);
405 while(getWrappedLine_remaining)
407 ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
411 pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
414 current_msg_posY = pos.y; // save starting pos (first line) of the current message
418 for(k = 0; k < n; ++k)
420 getWrappedLine_remaining = argv(k);
421 while(getWrappedLine_remaining)
423 ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
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();
435 pos.y += fontsize.y * CENTERPRINT_SPACING/2;
439 ++g; // move next position number up
441 msg_size = pos.y - msg_size;
442 if (autocvar_hud_panel_centerprint_flip)
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));
448 if (pos.y < panel_pos.y) // check if the next message can be shown
450 drawfontscale = hud_scale;
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));
460 if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
462 drawfontscale = hud_scale;
468 drawfontscale = hud_scale;
469 if (all_messages_expired)
471 centerprint_showing = false;
472 centerprint_KillAll();