1 /* $Id: hud.c,v 1.8 2003-10-10 09:36:35 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Routines for displaying HUD messages...
20 * Revision 1.4 1995/08/24 16:03:09 allender
21 * fix up message placement
23 * Revision 1.3 1995/08/18 10:25:21 allender
24 * added support for pixel doubling using PC game font
26 * Revision 1.2 1995/08/12 11:33:22 allender
27 * removed #ifdef NEWDEMO -- always in
29 * Revision 1.1 1995/05/16 15:26:32 allender
32 * Revision 2.2 1995/03/30 16:36:40 mike
35 * Revision 2.1 1995/03/06 15:23:50 john
36 * New screen techniques.
38 * Revision 2.0 1995/02/27 11:30:41 john
39 * New version 2.0, which has no anonymous unions, builds with
40 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
42 * Revision 1.27 1995/01/23 16:51:30 mike
43 * Show hud messages on 3d if window in three largest sizes.
45 * Revision 1.26 1995/01/17 17:42:45 rob
46 * Made message timeout for HUD messages longer.
48 * Revision 1.25 1995/01/04 11:39:03 rob
49 * Made HUD text get out of the way of large HUD messages.
51 * Revision 1.24 1995/01/01 14:20:32 rob
52 * longer timer for hud messages.
55 * Revision 1.23 1994/12/15 13:04:34 mike
56 * Replace Players[Player_num].time_total references with GameTime.
58 * Revision 1.22 1994/12/13 12:55:12 mike
59 * move press any key to continue message when you are dead to bottom of window.
61 * Revision 1.21 1994/12/07 17:08:01 rob
62 * removed unnecessary debug info.
64 * Revision 1.20 1994/12/07 16:24:16 john
65 * Took out code that kept track of messages differently for different
66 * screen modes... I made it so they just draw differently depending on screen mode.
68 * Revision 1.19 1994/12/07 15:42:57 rob
69 * Added a bunch of debug stuff to look for HUD message problems in net games...
71 * Revision 1.18 1994/12/06 16:30:35 yuan
74 * Revision 1.17 1994/12/05 00:32:36 mike
75 * fix randomness of color on status bar hud messages.
77 * Revision 1.16 1994/11/19 17:05:53 rob
78 * Moved dead_player_message down to avoid overwriting HUD messages.
80 * Revision 1.15 1994/11/18 23:37:56 john
81 * Changed some shorts to ints.
83 * Revision 1.14 1994/11/12 16:38:25 mike
84 * clear some annoying debug messages.
86 * Revision 1.13 1994/11/11 15:36:39 mike
87 * write hud messages on background if 3d window small enough
89 * Revision 1.12 1994/10/20 09:49:31 mike
90 * Reduce number of messages.
92 * Revision 1.11 1994/10/17 10:49:15 john
93 * Took out some warnings.
95 * Revision 1.10 1994/10/17 10:45:13 john
96 * Made the player able to abort death by pressing any button or key.
98 * Revision 1.9 1994/10/13 15:17:33 mike
99 * Remove afterburner references.
101 * Revision 1.8 1994/10/11 12:06:32 mike
102 * Only show message advertising death sequence abort after player exploded.
104 * Revision 1.7 1994/10/10 17:21:53 john
105 * Made so instead of saying too many messages, it scrolls off the
108 * Revision 1.6 1994/10/07 23:05:39 john
109 * Fixed bug with HUD not drawing stuff sometimes...
110 * ( I had a circular buffer that I was stepping thru
111 * to draw text that went: for (i=first;i<last;i++)...
112 * duh!! last could be less than first.)
115 * Revision 1.5 1994/09/16 13:08:20 mike
116 * Arcade stuff, afterburner stuff.
118 * Revision 1.4 1994/09/14 16:26:57 mike
119 * player_dead_message.
121 * Revision 1.3 1994/08/18 16:35:45 john
122 * Made gauges messages stay up a bit longer.
124 * Revision 1.2 1994/08/18 12:10:21 john
125 * Made HUD messages scroll.
127 * Revision 1.1 1994/08/18 11:22:09 john
155 #include "menu.h" // For the font.
160 #include "gamefont.h"
167 #include "pa_enabl.h"
172 int HUD_nmessages = 0;
173 fix HUD_message_timer = 0; // Time, relative to Players[Player_num].time (int.frac seconds.frac), at which to erase gauge message
174 char HUD_messages[HUD_MAX_NUM][HUD_MESSAGE_LENGTH+5];
176 extern void copy_background_rect(int left,int top,int right,int bot);
177 char Displayed_background_message[2][HUD_MESSAGE_LENGTH] = {"",""};
178 int Last_msg_ycrd = -1;
179 int Last_msg_height = 6;
182 int MSG_Playermessages = 0;
183 int MSG_Noredundancy = 0;
185 int Modex_hud_msg_count;
187 #define LHX(x) ((x)*(FontHires?2:1))
188 #define LHY(y) ((y)*(FontHires?2.4:1))
194 // ----------------------------------------------------------------------------
195 void clear_background_messages(void)
198 if (extra_clear == FrameCount) //don't do extra clear on same frame
203 if (((Cockpit_mode == CM_STATUS_BAR) || (Cockpit_mode == CM_FULL_SCREEN)) && (Last_msg_ycrd != -1) && (dd_VR_render_sub_buffer[0].yoff >= 6)) {
204 dd_grs_canvas *canv_save = dd_grd_curcanv;
206 if (((Cockpit_mode == CM_STATUS_BAR) || (Cockpit_mode == CM_FULL_SCREEN)) && (Last_msg_ycrd != -1) && (VR_render_sub_buffer[0].cv_bitmap.bm_y >= 6)) {
207 grs_canvas *canv_save = grd_curcanv;
210 WINDOS( dd_gr_set_current_canvas(get_current_game_screen()),
211 gr_set_current_canvas(get_current_game_screen())
214 PA_DFX (pa_set_frontbuffer_current());
215 PA_DFX (copy_background_rect(0, Last_msg_ycrd, grd_curcanv->cv_bitmap.bm_w, Last_msg_ycrd+Last_msg_height-1));
216 PA_DFX (pa_set_backbuffer_current());
217 copy_background_rect(0, Last_msg_ycrd, grd_curcanv->cv_bitmap.bm_w, Last_msg_ycrd+Last_msg_height-1);
220 dd_gr_set_current_canvas(canv_save),
221 gr_set_current_canvas(canv_save)
225 if (extra_clear || !GRMODEINFO(modex)) {
230 extra_clear = FrameCount;
236 Displayed_background_message[VR_current_page][0] = 0;
240 void HUD_clear_messages()
244 hud_first = hud_last = 0;
245 HUD_message_timer = 0;
246 clear_background_messages();
247 for (i = 0; i < HUD_MAX_NUM; i++)
248 sprintf(HUD_messages[i], "SlagelSlagel!!");
252 extern int Guided_in_big_window;
253 extern int max_window_h;
255 extern grs_canvas *print_to_canvas(char *s,grs_font *font, int fc, int bc, int double_flag);
257 // -----------------------------------------------------------------------------
258 // print to buffer, double heights, and blit bitmap to screen
259 void modex_hud_message(int x, int y, char *s, grs_font *font, int color)
261 grs_canvas *temp_canv;
263 temp_canv = print_to_canvas(s, font, color, -1, 1);
265 gr_bitmapm(x,y,&temp_canv->cv_bitmap);
267 gr_free_canvas(temp_canv);
270 extern int max_window_w;
272 // ----------------------------------------------------------------------------
273 // Writes a message on the HUD and checks its timer.
274 void HUD_render_message_frame()
279 if (( HUD_nmessages < 0 ) || (HUD_nmessages > HUD_MAX_NUM))
282 if ( (HUD_nmessages < 1 ) && (Modex_hud_msg_count == 0))
285 HUD_message_timer -= FrameTime;
289 clear_background_messages(); // If in status bar mode and no messages, then erase.
292 if ( HUD_message_timer < 0 ) {
293 // Timer expired... get rid of oldest message...
294 if (hud_last!=hud_first) {
297 //&HUD_messages[hud_first][0] is deing deleted...;
298 hud_first = (hud_first+1) % HUD_MAX_NUM;
299 HUD_message_timer = F1_0*2;
301 if (HUD_nmessages == 0)
302 Modex_hud_msg_count = 2;
303 temp = Last_msg_ycrd;
304 clear_background_messages(); // If in status bar mode and no messages, then erase.
305 if (Modex_hud_msg_count)
306 Last_msg_ycrd = temp;
310 if (HUD_nmessages > 0 ) {
313 HUD_color = BM_XRGB(0,28,0);
316 if ( (VR_render_mode==VR_NONE) && ((Cockpit_mode == CM_STATUS_BAR) || (Cockpit_mode == CM_FULL_SCREEN)) && (dd_VR_render_sub_buffer[0].yoff >= (max_window_h/8))) {
318 if ( (VR_render_mode==VR_NONE) && ((Cockpit_mode == CM_STATUS_BAR) || (Cockpit_mode == CM_FULL_SCREEN)) && (VR_render_sub_buffer[0].cv_bitmap.bm_y >= (max_window_h/8))) {
320 // Only display the most recent message in this mode
321 char *message = HUD_messages[(hud_first+HUD_nmessages-1) % HUD_MAX_NUM];
323 if (strcmp(Displayed_background_message[VR_current_page], message)) {
326 dd_grs_canvas *canv_save = dd_grd_curcanv,
327 grs_canvas *canv_save = grd_curcanv
332 FontHires=1; // always display hires font outside of display
336 ycrd = dd_grd_curcanv->yoff - (SMALL_FONT->ft_h+2),
337 ycrd = grd_curcanv->cv_bitmap.bm_y - (SMALL_FONT->ft_h+2)
344 dd_gr_set_current_canvas(get_current_game_screen()),
345 gr_set_current_canvas(get_current_game_screen())
348 gr_set_curfont( SMALL_FONT );
349 gr_get_string_size(message, &w, &h, &aw );
350 clear_background_messages();
353 if (grd_curcanv->cv_bitmap.bm_type == BM_MODEX) {
354 WIN(Int3()); // No no no no ....
357 modex_hud_message((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message, SMALL_FONT, HUD_color);
358 if (Modex_hud_msg_count > 0) {
359 Modex_hud_msg_count--;
360 Displayed_background_message[VR_current_page][0] = '!';
362 strcpy(Displayed_background_message[VR_current_page], message);
364 WIN(DDGRLOCK(dd_grd_curcanv));
365 gr_set_fontcolor( HUD_color, -1);
366 PA_DFX (pa_set_frontbuffer_current());
367 PA_DFX (gr_printf((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message ));
368 PA_DFX (pa_set_backbuffer_current());
369 gr_printf((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message );
370 strcpy(Displayed_background_message[VR_current_page], message);
371 WIN(DDGRUNLOCK(dd_grd_curcanv));
375 dd_gr_set_current_canvas(canv_save),
376 gr_set_current_canvas(canv_save)
379 Last_msg_ycrd = ycrd;
384 FontHires=0; // always display hires font outside of display
390 gr_set_curfont( SMALL_FONT );
392 if ( (Cockpit_mode == CM_FULL_SCREEN) || (Cockpit_mode == CM_LETTERBOX) ) {
393 if (Game_window_w == max_window_w)
394 y = SMALL_FONT->ft_h/2;
396 y= SMALL_FONT->ft_h * 2;
398 y = SMALL_FONT->ft_h/2;
400 if (Guided_missile[Player_num] && Guided_missile[Player_num]->type==OBJ_WEAPON && Guided_missile[Player_num]->id==GUIDEDMISS_ID &&
401 Guided_missile[Player_num]->signature==Guided_missile_sig[Player_num] && Guided_in_big_window)
402 y+=SMALL_FONT->ft_h+3;
404 WIN(DDGRLOCK(dd_grd_curcanv));
405 for (i=0; i<HUD_nmessages; i++ ) {
406 n = (hud_first+i) % HUD_MAX_NUM;
407 if ((n < 0) || (n >= HUD_MAX_NUM))
409 if (!strcmp(HUD_messages[n], "This is a bug."))
411 gr_get_string_size(&HUD_messages[n][0], &w, &h, &aw );
412 gr_set_fontcolor( HUD_color, -1);
414 PA_DFX (pa_set_frontbuffer_current());
415 PA_DFX(gr_string((grd_curcanv->cv_bitmap.bm_w-w)/2,y, &HUD_messages[n][0] ));
416 PA_DFX (pa_set_backbuffer_current());
417 gr_string((grd_curcanv->cv_bitmap.bm_w-w)/2,y, &HUD_messages[n][0] );
420 WIN(DDGRUNLOCK(dd_grd_curcanv));
424 else if (get_current_game_screen()->cv_bitmap.bm_type == BM_MODEX) {
425 if (Modex_hud_msg_count) {
426 int temp = Last_msg_ycrd;
427 Modex_hud_msg_count--;
428 clear_background_messages(); // If in status bar mode and no messages, then erase.
429 Last_msg_ycrd = temp;
434 gr_set_curfont( GAME_FONT );
440 // Call to flash a message on the HUD. Returns true if message drawn.
441 // (message might not be drawn if previous message was same)
442 int HUD_init_message_va(char * format, va_list args)
445 char *message = NULL;
446 char *last_message=NULL;
451 char con_message[HUD_MESSAGE_LENGTH + 3];
453 Modex_hud_msg_count = 2;
455 if ( (hud_last < 0) || (hud_last >= HUD_MAX_NUM))
458 // -- mprintf((0, "message timer: %7.3f\n", f2fl(HUD_message_timer)));
459 message = &HUD_messages[hud_last][0];
460 vsprintf(message,format,args);
463 /* Produce a colorised version and send it to the console */
465 HUD_color = BM_XRGB(0,28,0);
466 con_message[0] = CC_COLOR;
467 con_message[1] = HUD_color;
468 con_message[2] = '\0';
469 strcat(con_message, message);
470 con_printf(CON_NORMAL, "%s\n", con_message);
474 if ((Game_mode & GM_MULTI) && FindArg("-noredundancy"))
475 if (!strnicmp ("You already",message,11))
478 if ((Game_mode & GM_MULTI) && FindArg("-PlayerMessages") && PlayerMessage==0)
481 if (HUD_nmessages > 0) {
483 last_message = &HUD_messages[HUD_MAX_NUM-1][0];
485 last_message = &HUD_messages[hud_last-1][0];
488 temp = (hud_last+1) % HUD_MAX_NUM;
490 if ( temp==hud_first ) {
491 // If too many messages, remove oldest message to make room
492 hud_first = (hud_first+1) % HUD_MAX_NUM;
496 if (last_message && (!strcmp(last_message, message))) {
497 HUD_message_timer = F1_0*3; // 1 second per 5 characters
498 return 0; // ignore since it is the same as the last one
502 // Check if memory has been overwritten at this point.
503 if (strlen(message) >= HUD_MESSAGE_LENGTH)
504 Error( "Your message to HUD is too long. Limit is %i characters.\n", HUD_MESSAGE_LENGTH);
506 if (Newdemo_state == ND_STATE_RECORDING )
507 newdemo_record_hud_message( message );
509 HUD_message_timer = F1_0*3; // 1 second per 5 characters
516 int HUD_init_message(char * format, ... )
521 va_start(args, format);
522 ret = HUD_init_message_va(format, args);
529 //@@void player_dead_message(void)
531 //@@ if (!Arcade_mode && Player_exploded) { //(ConsoleObject->flags & OF_EXPLODING)) {
532 //@@ gr_set_curfont( SMALL_FONT );
533 //@@ if (HUD_color == -1)
534 //@@ HUD_color = BM_XRGB(0,28,0);
535 //@@ gr_set_fontcolor( HUD_color, -1);
537 //@@ gr_printf(0x8000, grd_curcanv->cv_bitmap.bm_h-8, TXT_PRESS_ANY_KEY);
538 //@@ gr_set_curfont( GAME_FONT );
543 void player_dead_message(void)
545 if (Player_exploded) {
546 if ( Players[Player_num].lives < 2 ) {
548 gr_set_curfont( HUGE_FONT );
549 gr_get_string_size( TXT_GAME_OVER, &w, &h, &aw );
552 x = (grd_curcanv->cv_w - w ) / 2;
553 y = (grd_curcanv->cv_h - h ) / 2;
555 NO_DFX (Gr_scanline_darkening_level = 2*7);
556 NO_DFX (gr_setcolor( BM_XRGB(0,0,0) ));
557 NO_DFX (gr_rect( x, y, x+w, y+h ));
558 Gr_scanline_darkening_level = GR_FADE_LEVELS;
560 gr_string(0x8000, (grd_curcanv->cv_h - grd_curcanv->cv_font->ft_h)/2 + h/8, TXT_GAME_OVER );
563 // Automatically exit death after 10 secs
564 if ( GameTime > Player_time_of_death + F1_0*10 ) {
565 Function_mode = FMODE_MENU;
566 Game_mode = GM_GAME_OVER;
567 longjmp( LeaveGame, 1 ); // Exit out of game loop
572 gr_set_curfont( GAME_FONT );
574 HUD_color = BM_XRGB(0,28,0);
575 gr_set_fontcolor( HUD_color, -1);
576 gr_string(0x8000, grd_curcanv->cv_h-(grd_curcanv->cv_font->ft_h+3), TXT_PRESS_ANY_KEY);
580 // void say_afterburner_status(void)
582 // if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
583 // HUD_init_message("Afterburner engaged.");
585 // HUD_init_message("Afterburner disengaged.");
588 void hud_message(int class, char *format, ...)
592 va_start(vp, format);
593 if ((!MSG_Noredundancy || (class & MSGC_NOREDUNDANCY)) &&
594 (!MSG_Playermessages || !(Game_mode & GM_MULTI) ||
595 (class & MSGC_PLAYERMESSAGES)))
596 HUD_init_message_va(format, vp);