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