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