whitespace
[btb/d2x.git] / main / hud.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  * $Source: /cvs/cvsroot/d2x/main/hud.c,v $
16  * $Revision: 1.5 $
17  * $Author: btb $
18  * $Date: 2002-10-11 05:14:59 $
19  *
20  * Routines for displaying HUD messages...
21  *
22  * $Log: not supported by cvs2svn $
23  * Revision 1.4  2002/10/10 19:08:15  btb
24  * whitespace
25  *
26  * Revision 1.3  2001/11/04 09:00:25  bradleyb
27  * Enable d1x-style hud_message
28  *
29  *
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include <conf.h>
34 #endif
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40
41 #include "hudmsg.h"
42
43 #include "pstypes.h"
44 #include "u_mem.h"
45 #include "strutil.h"
46 #include "console.h"
47 #include "inferno.h"
48 #include "game.h"
49 #include "screens.h"
50 #include "gauges.h"
51 #include "physics.h"
52 #include "error.h"
53
54 #include "menu.h"                       // For the font.
55 #include "mono.h"
56 #include "collide.h"
57 #include "newdemo.h"
58 #include "player.h"
59 #include "gamefont.h"
60
61 #include "wall.h"
62 #include "screens.h"
63 #include "text.h"
64 #include "laser.h"
65 #include "args.h"
66 #include "pa_enabl.h"
67
68 int hud_first = 0;
69 int hud_last = 0;
70
71 int     HUD_nmessages = 0;
72 fix     HUD_message_timer = 0;          // Time, relative to Players[Player_num].time (int.frac seconds.frac), at which to erase gauge message
73 char  HUD_messages[HUD_MAX_NUM][HUD_MESSAGE_LENGTH+5];
74
75 extern void copy_background_rect(int left,int top,int right,int bot);
76 char Displayed_background_message[2][HUD_MESSAGE_LENGTH] = {"",""};
77 int     Last_msg_ycrd = -1;
78 int     Last_msg_height = 6;
79 int     HUD_color = -1;
80
81 int     MSG_Playermessages = 0;
82 int     MSG_Noredundancy = 0;
83
84 int     Modex_hud_msg_count;
85
86 #define LHX(x)          ((x)*(FontHires?2:1))
87 #define LHY(y)          ((y)*(FontHires?2.4:1))
88
89 #ifdef WINDOWS
90 int extra_clear=0;
91 #endif
92
93 //      -----------------------------------------------------------------------------
94 void clear_background_messages(void)
95 {
96         #ifdef WINDOWS
97         if (extra_clear == FrameCount)          //don't do extra clear on same frame
98                 return;
99         #endif
100
101 #ifdef WINDOWS
102         if (((Cockpit_mode == CM_STATUS_BAR) || (Cockpit_mode == CM_FULL_SCREEN)) && (Last_msg_ycrd != -1) && (dd_VR_render_sub_buffer[0].yoff >= 6)) {
103                 dd_grs_canvas *canv_save = dd_grd_curcanv;
104 #else
105         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)) {
106                 grs_canvas      *canv_save = grd_curcanv;
107 #endif    
108
109                 WINDOS( dd_gr_set_current_canvas(get_current_game_screen()),
110                                 gr_set_current_canvas(get_current_game_screen())
111                 );
112
113                 PA_DFX (pa_set_frontbuffer_current());
114                 PA_DFX (copy_background_rect(0, Last_msg_ycrd, grd_curcanv->cv_bitmap.bm_w, Last_msg_ycrd+Last_msg_height-1));
115                 PA_DFX (pa_set_backbuffer_current());
116                 copy_background_rect(0, Last_msg_ycrd, grd_curcanv->cv_bitmap.bm_w, Last_msg_ycrd+Last_msg_height-1);
117           
118                 WINDOS( 
119                         dd_gr_set_current_canvas(canv_save),
120                         gr_set_current_canvas(canv_save)
121                 );
122
123                 #ifdef WINDOWS
124                 if (extra_clear || !GRMODEINFO(modex)) {
125                         extra_clear = 0;
126                         Last_msg_ycrd = -1;
127                 }
128                 else
129                         extra_clear = FrameCount;
130                 #else
131                 Last_msg_ycrd = -1;
132                 #endif
133         }
134
135         Displayed_background_message[VR_current_page][0] = 0;
136
137 }
138
139 void HUD_clear_messages()
140 {
141         int i;
142         HUD_nmessages = 0;
143         hud_first = hud_last = 0;
144         HUD_message_timer = 0;
145         clear_background_messages();
146         for (i = 0; i < HUD_MAX_NUM; i++)
147                 sprintf(HUD_messages[i], "SlagelSlagel!!");
148 }
149
150
151 extern int Guided_in_big_window;
152 extern int max_window_h;
153
154 extern grs_canvas *print_to_canvas(char *s,grs_font *font, int fc, int bc, int double_flag);
155
156 //      -----------------------------------------------------------------------------
157 //      print to buffer, double heights, and blit bitmap to screen
158 void modex_hud_message(int x, int y, char *s, grs_font *font, int color)
159 {
160         grs_canvas *temp_canv;
161
162         temp_canv = print_to_canvas(s, font, color, -1, 1);
163
164         gr_bitmapm(x,y,&temp_canv->cv_bitmap);
165
166         gr_free_canvas(temp_canv);
167 }
168
169 extern int max_window_w;
170
171 //      -----------------------------------------------------------------------------
172 //      Writes a message on the HUD and checks its timer.
173 void HUD_render_message_frame()
174 {
175         int i, y,n;
176         int h,w,aw;
177
178         if (( HUD_nmessages < 0 ) || (HUD_nmessages > HUD_MAX_NUM))
179                 Int3(); // Get Rob!
180
181         if ( (HUD_nmessages < 1 ) && (Modex_hud_msg_count == 0))
182                 return;
183
184         HUD_message_timer -= FrameTime;
185
186         #ifdef WINDOWS
187         if (extra_clear)
188                 clear_background_messages();                    //      If in status bar mode and no messages, then erase.
189         #endif
190
191         if ( HUD_message_timer < 0 )    {
192                 // Timer expired... get rid of oldest message...
193                 if (hud_last!=hud_first)        {
194                         int     temp;
195
196                         //&HUD_messages[hud_first][0] is deing deleted...;
197                         hud_first = (hud_first+1) % HUD_MAX_NUM;
198                         HUD_message_timer = F1_0*2;
199                         HUD_nmessages--;
200                         if (HUD_nmessages == 0)
201                                 Modex_hud_msg_count = 2;
202                         temp = Last_msg_ycrd;
203                         clear_background_messages();                    //      If in status bar mode and no messages, then erase.
204                         if (Modex_hud_msg_count)
205                                 Last_msg_ycrd = temp;
206                 }
207         }
208
209         if (HUD_nmessages > 0 ) {
210
211                 if (HUD_color == -1)
212                         HUD_color = BM_XRGB(0,28,0);
213
214         #ifdef WINDOWS
215                 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))) {
216         #else
217                 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))) {
218         #endif
219                         // Only display the most recent message in this mode
220                         char    *message = HUD_messages[(hud_first+HUD_nmessages-1) % HUD_MAX_NUM];
221
222                         if (strcmp(Displayed_background_message[VR_current_page], message)) {
223                                 int     ycrd;
224                                 WINDOS(
225                                         dd_grs_canvas *canv_save = dd_grd_curcanv,
226                                         grs_canvas      *canv_save = grd_curcanv
227                                 );
228
229                                 #ifdef MACINTOSH
230                                 if (Scanline_double)
231                                         FontHires=1;    // always display hires font outside of display
232                                 #endif
233
234                                 WINDOS(
235                                         ycrd = dd_grd_curcanv->yoff - (SMALL_FONT->ft_h+2),
236                                         ycrd = grd_curcanv->cv_bitmap.bm_y - (SMALL_FONT->ft_h+2)
237                                 );
238
239                                 if (ycrd < 0)
240                                         ycrd = 0;
241
242                                 WINDOS(
243                                         dd_gr_set_current_canvas(get_current_game_screen()),
244                                         gr_set_current_canvas(get_current_game_screen())
245                                 );
246
247                                 gr_set_curfont( SMALL_FONT );
248                                 gr_get_string_size(message, &w, &h, &aw );
249                                 clear_background_messages();
250
251
252                                 if (grd_curcanv->cv_bitmap.bm_type == BM_MODEX) {
253                                         WIN(Int3());    // No no no no ....
254                                         ycrd -= h;
255                                         h *= 2;
256                                         modex_hud_message((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message, SMALL_FONT, HUD_color);
257                                         if (Modex_hud_msg_count > 0) {
258                                                 Modex_hud_msg_count--;
259                                                 Displayed_background_message[VR_current_page][0] = '!';
260                                         } else
261                                                 strcpy(Displayed_background_message[VR_current_page], message);
262                                 } else {
263                                 WIN(DDGRLOCK(dd_grd_curcanv));
264                                         gr_set_fontcolor( HUD_color, -1);
265                                         PA_DFX (pa_set_frontbuffer_current());
266                                         PA_DFX (gr_printf((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message ));
267                                         PA_DFX (pa_set_backbuffer_current());
268                                         gr_printf((grd_curcanv->cv_bitmap.bm_w-w)/2, ycrd, message );
269                                         strcpy(Displayed_background_message[VR_current_page], message);
270                                 WIN(DDGRUNLOCK(dd_grd_curcanv));
271                                 }
272
273                         WINDOS(
274                                 dd_gr_set_current_canvas(canv_save),
275                                 gr_set_current_canvas(canv_save)
276                         );
277
278                                 Last_msg_ycrd = ycrd;
279                                 Last_msg_height = h;
280
281                                 #ifdef MACINTOSH
282                                 if (Scanline_double)
283                                         FontHires=0;    // always display hires font outside of display
284                                 #endif
285
286                         }
287                 } else {
288
289                         gr_set_curfont( SMALL_FONT );
290
291                         if ( (Cockpit_mode == CM_FULL_SCREEN) || (Cockpit_mode == CM_LETTERBOX) ) {
292                                 if (Game_window_w == max_window_w)
293                                         y = SMALL_FONT->ft_h/2;
294                                 else
295                                         y= SMALL_FONT->ft_h * 2;
296                         } else
297                                 y = SMALL_FONT->ft_h/2;
298
299                   if (Guided_missile[Player_num] && Guided_missile[Player_num]->type==OBJ_WEAPON && Guided_missile[Player_num]->id==GUIDEDMISS_ID &&
300                       Guided_missile[Player_num]->signature==Guided_missile_sig[Player_num] && Guided_in_big_window)
301                               y+=SMALL_FONT->ft_h+3; 
302
303                 WIN(DDGRLOCK(dd_grd_curcanv));
304                         for (i=0; i<HUD_nmessages; i++ )        {       
305                                 n = (hud_first+i) % HUD_MAX_NUM;
306                                 if ((n < 0) || (n >= HUD_MAX_NUM))
307                                         Int3(); // Get Rob!!
308                                 if (!strcmp(HUD_messages[n], "This is a bug."))
309                                         Int3(); // Get Rob!!
310                                 gr_get_string_size(&HUD_messages[n][0], &w, &h, &aw );
311                                 gr_set_fontcolor( HUD_color, -1);
312                         
313                                 PA_DFX (pa_set_frontbuffer_current());
314                                 PA_DFX(gr_string((grd_curcanv->cv_bitmap.bm_w-w)/2,y, &HUD_messages[n][0] ));
315                                 PA_DFX (pa_set_backbuffer_current());
316                                 gr_string((grd_curcanv->cv_bitmap.bm_w-w)/2,y, &HUD_messages[n][0] );
317                                 y += h+1;
318                         }
319                 WIN(DDGRUNLOCK(dd_grd_curcanv));
320                 }
321         }
322         #ifndef WINDOWS
323         else if (get_current_game_screen()->cv_bitmap.bm_type == BM_MODEX) {
324                 if (Modex_hud_msg_count) {
325                         int     temp = Last_msg_ycrd;
326                         Modex_hud_msg_count--;
327                         clear_background_messages();                    //      If in status bar mode and no messages, then erase.
328                         Last_msg_ycrd = temp;
329                 }
330         }
331         #endif
332
333         gr_set_curfont( GAME_FONT );
334 }
335
336 int PlayerMessage=1;
337
338
339 // Call to flash a message on the HUD.  Returns true if message drawn.
340 //  (message might not be drawn if previous message was same)
341 int HUD_init_message_va(char * format, va_list args)
342 {
343         int temp, temp2;
344         char *message = NULL;
345         char *last_message=NULL;
346         char *cleanmessage;
347
348         Modex_hud_msg_count = 2;
349
350         if ( (hud_last < 0) || (hud_last >= HUD_MAX_NUM))
351                 Int3(); // Get Rob!!
352
353         // -- mprintf((0, "message timer: %7.3f\n", f2fl(HUD_message_timer)));
354         message = &HUD_messages[hud_last][0];
355         vsprintf(message,format,args);
356
357         /* Produce a sanitised version and send it to the console */
358         cleanmessage = d_strdup(message);
359         for (temp=0,temp2=0; message[temp]!=0; temp++)
360         {
361                 if (isprint(message[temp])) cleanmessage[temp2++] = message[temp];
362                 else temp++; /* Skip next character as well */
363         }
364         cleanmessage[temp2] = 0;
365         con_printf(CON_NORMAL, "%s\n", message);
366         d_free(cleanmessage);
367
368         // Added by Leighton 
369    
370    if ((Game_mode & GM_MULTI) && FindArg("-noredundancy"))
371          if (!strnicmp ("You already",message,11))
372                 return 0;
373
374    if ((Game_mode & GM_MULTI) && FindArg("-PlayerMessages") && PlayerMessage==0)
375                 return 0;
376   
377         if (HUD_nmessages > 0)  {
378                 if (hud_last==0)
379                         last_message = &HUD_messages[HUD_MAX_NUM-1][0];
380                 else
381                         last_message = &HUD_messages[hud_last-1][0];
382         }
383
384         temp = (hud_last+1) % HUD_MAX_NUM;
385
386         if ( temp==hud_first )  {
387                 // If too many messages, remove oldest message to make room
388                 hud_first = (hud_first+1) % HUD_MAX_NUM;
389                 HUD_nmessages--;
390         }
391
392         if (last_message && (!strcmp(last_message, message))) {
393                 HUD_message_timer = F1_0*3;             // 1 second per 5 characters
394                 return 0;       // ignore since it is the same as the last one
395         }
396
397         hud_last = temp;
398         // Check if memory has been overwritten at this point.
399         if (strlen(message) >= HUD_MESSAGE_LENGTH)
400                 Error( "Your message to HUD is too long.  Limit is %i characters.\n", HUD_MESSAGE_LENGTH);
401         #ifdef NEWDEMO
402         if (Newdemo_state == ND_STATE_RECORDING )
403                 newdemo_record_hud_message( message );
404         #endif
405         HUD_message_timer = F1_0*3;             // 1 second per 5 characters
406         HUD_nmessages++;
407
408         return 1;
409 }
410
411
412 int HUD_init_message(char * format, ... )
413 {
414         int ret;
415         va_list args;
416
417         va_start(args, format);
418         ret = HUD_init_message_va(format, args);
419         va_end(args);
420
421         return ret;
422 }
423
424
425 //@@void player_dead_message(void)
426 //@@{
427 //@@    if (!Arcade_mode && Player_exploded) { //(ConsoleObject->flags & OF_EXPLODING)) {
428 //@@            gr_set_curfont( SMALL_FONT );    
429 //@@            if (HUD_color == -1)
430 //@@                    HUD_color = BM_XRGB(0,28,0);
431 //@@            gr_set_fontcolor( HUD_color, -1);
432 //@@
433 //@@            gr_printf(0x8000, grd_curcanv->cv_bitmap.bm_h-8, TXT_PRESS_ANY_KEY);
434 //@@            gr_set_curfont( GAME_FONT );    
435 //@@    }
436 //@@
437 //@@}
438
439 void player_dead_message(void)
440 {
441     if (Player_exploded) {      
442         if ( Players[Player_num].lives < 2 )    {
443             int x, y, w, h, aw;
444             gr_set_curfont( HUGE_FONT );    
445             gr_get_string_size( TXT_GAME_OVER, &w, &h, &aw );
446             w += 20;
447             h += 8;
448             x = (grd_curcanv->cv_w - w ) / 2;
449             y = (grd_curcanv->cv_h - h ) / 2;
450             
451             NO_DFX (Gr_scanline_darkening_level = 2*7);
452             NO_DFX (gr_setcolor( BM_XRGB(0,0,0) ));
453             NO_DFX (gr_rect( x, y, x+w, y+h ));
454             Gr_scanline_darkening_level = GR_FADE_LEVELS;
455
456             gr_string(0x8000, (grd_curcanv->cv_h - grd_curcanv->cv_font->ft_h)/2 + h/8, TXT_GAME_OVER );
457
458 #if 0
459             // Automatically exit death after 10 secs
460             if ( GameTime > Player_time_of_death + F1_0*10 ) {
461                     Function_mode = FMODE_MENU;
462                     Game_mode = GM_GAME_OVER;
463                     longjmp( LeaveGame, 1 );        // Exit out of game loop
464             }
465 #endif
466
467         } 
468         gr_set_curfont( GAME_FONT );    
469         if (HUD_color == -1)
470             HUD_color = BM_XRGB(0,28,0);
471         gr_set_fontcolor( HUD_color, -1);
472         gr_string(0x8000, grd_curcanv->cv_h-(grd_curcanv->cv_font->ft_h+3), TXT_PRESS_ANY_KEY);
473     }
474 }
475
476 // void say_afterburner_status(void)
477 // {
478 //      if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
479 //              HUD_init_message("Afterburner engaged.");
480 //      else
481 //              HUD_init_message("Afterburner disengaged.");
482 // }
483
484 void hud_message(int class, char *format, ...)
485 {
486         va_list vp;
487
488         va_start(vp, format);
489         if ((!MSG_Noredundancy || (class & MSGC_NOREDUNDANCY)) &&
490             (!MSG_Playermessages || !(Game_mode & GM_MULTI) ||
491              (class & MSGC_PLAYERMESSAGES)))
492                 HUD_init_message_va(format, vp);
493         va_end(vp);
494 }
495