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