1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:  Heads-up displays
30  *
31  *-----------------------------------------------------------------------------
32  */
33 
34 // killough 5/3/98: remove unnecessary headers
35 
36 #include "doomstat.h"
37 #include "hu_stuff.h"
38 #include "hu_lib.h"
39 #include "hu_tracers.h"
40 #include "st_stuff.h" /* jff 2/16/98 need loc of status bar */
41 #include "s_sound.h"
42 #include "dstrings.h"
43 #include "sounds.h"
44 #include "d_deh.h"   /* Ty 03/27/98 - externalization of mapnamesx arrays */
45 #include "g_game.h"
46 #include "r_main.h"
47 #include "p_inter.h"
48 #include "sc_man.h"
49 #include "lprintf.h"
50 #include "e6y.h" //e6y
51 
52 // global heads up display controls
53 
54 int hud_displayed;    //jff 2/23/98 turns heads-up display on/off
55 int hud_num;
56 
57 //
58 // Locally used constants, shortcuts.
59 //
60 // Ty 03/28/98 -
61 // These four shortcuts modifed to reflect char ** of mapnamesx[]
62 // e6y: why sizeof(mapnamest)/sizeof(mapnamest[0]) does not work?
63 #define HU_TITLE  (*mapnames[(gameepisode-1)*9+gamemap-1])
64 #define HU_TITLE2 (gamemap <= 32 ? *mapnames2[gamemap-1] : "")
65 #define HU_TITLEP (gamemap <= 32 ? *mapnamesp[gamemap-1] : "")
66 #define HU_TITLET (gamemap <= 32 ? *mapnamest[gamemap-1] : "")
67 #define HU_TITLEX 0
68 //jff 2/16/98 change 167 to ST_Y-1
69 // CPhipps - changed to ST_TY
70 // proff - changed to 200-ST_HEIGHT for stretching
71 #define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height)
72 
73 //jff 2/16/98 add coord text widget coordinates
74 // proff - changed to SCREENWIDTH to 320 for stretching
75 #define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width)
76 //jff 3/3/98 split coord widget into three lines in upper right of screen
77 #define HU_COORDXYZ_Y (1 * hu_font['A'-HU_FONTSTART].height + 1)
78 #define HU_COORDX_Y (0 + 0*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y)
79 #define HU_COORDY_Y (1 + 1*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y)
80 #define HU_COORDZ_Y (2 + 2*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y)
81 
82 #define HU_MAP_STAT_X (0)
83 #define HU_MAP_STAT_Y (1 * hu_font['A'-HU_FONTSTART].height + 1)
84 #define HU_MAP_MONSTERS_Y  (0 + 0*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y)
85 #define HU_MAP_SECRETS_Y   (1 + 1*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y)
86 #define HU_MAP_ITEMS_Y     (2 + 2*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y)
87 #define HU_MAP_TIME_Y      (4 + 4*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y)
88 #define HU_MAP_TOTALTIME_Y (5 + 5*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y)
89 
90 //jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap
91 #define HU_GAPY 8
92 
93 #define HU_INPUTX HU_MSGX
94 #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1)
95 
96 #define HU_TRACERX (2)
97 #define HU_TRACERY (hu_font['A'-HU_FONTSTART].height)
98 
99 #define key_alt KEYD_RALT
100 #define key_shift KEYD_RSHIFT
101 
102 const char* chat_macros[] =
103 // Ty 03/27/98 - *not* externalized
104 // CPhipps - const char*
105 {
106   HUSTR_CHATMACRO0,
107   HUSTR_CHATMACRO1,
108   HUSTR_CHATMACRO2,
109   HUSTR_CHATMACRO3,
110   HUSTR_CHATMACRO4,
111   HUSTR_CHATMACRO5,
112   HUSTR_CHATMACRO6,
113   HUSTR_CHATMACRO7,
114   HUSTR_CHATMACRO8,
115   HUSTR_CHATMACRO9
116 };
117 
118 const char* player_names[] =
119 // Ty 03/27/98 - *not* externalized
120 // CPhipps - const char*
121 {
122   HUSTR_PLRGREEN,
123   HUSTR_PLRINDIGO,
124   HUSTR_PLRBROWN,
125   HUSTR_PLRRED
126 };
127 
128 //jff 3/17/98 translate player colmap to text color ranges
129 int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED};
130 
131 char chat_char;                 // remove later.
132 static player_t*  plr;
133 
134 // font sets
135 patchnum_t hu_font[HU_FONTSIZE];
136 patchnum_t hu_font2[HU_FONTSIZE];
137 patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators
138 patchnum_t hu_msgbg[9];          //jff 2/26/98 add patches for message background
139 patchnum_t hu_font_hud[HU_FONTSIZE];
140 
141 // widgets
142 static hu_textline_t  w_title;
143 static hu_stext_t     w_message;
144 static hu_itext_t     w_chat;
145 static hu_itext_t     w_inputbuffer[MAXPLAYERS];
146 static hu_textline_t  w_coordx; //jff 2/16/98 new coord widget for automap
147 static hu_textline_t  w_coordy; //jff 3/3/98 split coord widgets automap
148 static hu_textline_t  w_coordz; //jff 3/3/98 split coord widgets automap
149 static hu_textline_t  w_ammo;   //jff 2/16/98 new ammo widget for hud
150 static hu_textline_t  w_health; //jff 2/16/98 new health widget for hud
151 static hu_textline_t  w_armor;  //jff 2/16/98 new armor widget for hud
152 static hu_textline_t  w_weapon; //jff 2/16/98 new weapon widget for hud
153 static hu_textline_t  w_keys;   //jff 2/16/98 new keys widget for hud
154 static hu_textline_t  w_gkeys;  //jff 3/7/98 graphic keys widget for hud
155 static hu_textline_t  w_monsec; //jff 2/16/98 new kill/secret widget for hud
156 static hu_mtext_t     w_rtext;  //jff 2/26/98 text message refresh widget
157 
158 static hu_textline_t  w_map_monsters;  //e6y monsters widget for automap
159 static hu_textline_t  w_map_secrets;   //e6y secrets widgets automap
160 static hu_textline_t  w_map_items;     //e6y items widgets automap
161 static hu_textline_t  w_map_time;      //e6y level time widgets automap
162 static hu_textline_t  w_map_totaltime; //e6y total time widgets automap
163 
164 static hu_textline_t  w_health_big;
165 static hu_textline_t  w_medict_icon_big;
166 static hu_textline_t  w_medict_icon_small;
167 static hu_textline_t  w_medict_icon_custom;
168 static hu_textline_t  w_armor_big;
169 static hu_textline_t  w_armor_icon_big;
170 static hu_textline_t  w_armor_icon_small;
171 static hu_textline_t  w_armor_icon_custom;
172 static hu_textline_t  w_medict_percent;
173 static hu_textline_t  w_armor_percent;
174 static hu_textline_t  w_ammo_big;
175 static hu_textline_t  w_ammo_icon;
176 static hu_textline_t  w_keys_icon;
177 
178 static dboolean    always_off = false;
179 static char       chat_dest[MAXPLAYERS];
180 dboolean           chat_on;
181 static dboolean    message_on;
182 static dboolean    message_list; //2/26/98 enable showing list of messages
183 dboolean           message_dontfuckwithme;
184 static dboolean    message_nottobefuckedwith;
185 static int        message_counter;
186 extern int        showMessages;
187 static dboolean    headsupactive = false;
188 
189 //jff 2/16/98 hud supported automap colors added
190 int hudcolor_titl;  // color range of automap level title
191 int hudcolor_xyco;  // color range of new coords on automap
192 int hudcolor_mapstat_title;
193 int hudcolor_mapstat_value;
194 int hudcolor_mapstat_time;
195 //jff 2/16/98 hud text colors, controls added
196 int hudcolor_mesg;  // color range of scrolling messages
197 int hudcolor_chat;  // color range of chat lines
198 int hud_msg_lines;  // number of message lines in window
199 //jff 2/26/98 hud text colors, controls added
200 int hudcolor_list;  // list of messages color
201 int hud_list_bgon;  // enable for solid window background for message list
202 
203 //jff 2/16/98 initialization strings for ammo, health, armor widgets
204 static char hud_coordstrx[32];
205 static char hud_coordstry[32];
206 static char hud_coordstrz[32];
207 static char hud_ammostr[80];
208 static char hud_healthstr[80];
209 static char hud_armorstr[80];
210 static char hud_weapstr[80];
211 static char hud_keysstr[80];
212 static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display
213 static char hud_monsecstr[80];
214 
215 //
216 // Builtin map names.
217 // The actual names can be found in DStrings.h.
218 //
219 // Ty 03/27/98 - externalized map name arrays - now in d_deh.c
220 // and converted to arrays of pointers to char *
221 // See modified HUTITLEx macros
222 extern char **mapnames[];
223 extern char **mapnames2[];
224 extern char **mapnamesp[];
225 extern char **mapnamest[];
226 
227 extern int map_point_coordinates;
228 extern int map_level_stat;
229 
230 // key tables
231 // jff 5/10/98 french support removed,
232 // as it was not being used and couldn't be easily tested
233 //
234 const char* shiftxform;
235 
236 const char english_shiftxform[] =
237 {
238   0,
239   1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
240   11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
241   21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
242   31,
243   ' ', '!', '"', '#', '$', '%', '&',
244   '"', // shift-'
245   '(', ')', '*', '+',
246   '<', // shift-,
247   '_', // shift--
248   '>', // shift-.
249   '?', // shift-/
250   ')', // shift-0
251   '!', // shift-1
252   '@', // shift-2
253   '#', // shift-3
254   '$', // shift-4
255   '%', // shift-5
256   '^', // shift-6
257   '&', // shift-7
258   '*', // shift-8
259   '(', // shift-9
260   ':',
261   ':', // shift-;
262   '<',
263   '+', // shift-=
264   '>', '?', '@',
265   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
266   'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
267   '[', // shift-[
268   '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
269   ']', // shift-]
270   '"', '_',
271   '\'', // shift-`
272   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
273   'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
274   '{', '|', '}', '~', 127
275 };
276 
277 //
278 // HU_Init()
279 //
280 // Initialize the heads-up display, text that overwrites the primary display
281 //
282 // Passed nothing, returns nothing
283 //
HU_Init(void)284 void HU_Init(void)
285 {
286 
287   int   i;
288   int   j;
289   char  buffer[9];
290 
291   shiftxform = english_shiftxform;
292 
293   // load the heads-up font
294   j = HU_FONTSTART;
295   for (i=0;i<HU_FONTSIZE;i++,j++)
296   {
297     if ('0'<=j && j<='9')
298     {
299       sprintf(buffer, "DIG%.1d",j-48);
300       R_SetPatchNum(&hu_font2[i], buffer);
301       sprintf(buffer, "STCFN%.3d",j);
302       R_SetPatchNum(&hu_font[i], buffer);
303       sprintf(buffer, "STTNUM%.1d",j-48);
304       R_SetPatchNum(&hu_font_hud[i], buffer);
305     }
306     else if ('A'<=j && j<='Z')
307     {
308       sprintf(buffer, "DIG%c",j);
309       R_SetPatchNum(&hu_font2[i], buffer);
310       sprintf(buffer, "STCFN%.3d",j);
311       R_SetPatchNum(&hu_font[i], buffer);
312     }
313     else if (j=='-')
314     {
315       R_SetPatchNum(&hu_font2[i], "DIG45");
316       R_SetPatchNum(&hu_font[i], "STCFN045");
317     }
318     else if (j=='/')
319     {
320       R_SetPatchNum(&hu_font2[i], "DIG47");
321       R_SetPatchNum(&hu_font[i], "STCFN047");
322     }
323     else if (j==':')
324     {
325       R_SetPatchNum(&hu_font2[i], "DIG58");
326       R_SetPatchNum(&hu_font[i], "STCFN058");
327     }
328     else if (j=='[')
329     {
330       R_SetPatchNum(&hu_font2[i], "DIG91");
331       R_SetPatchNum(&hu_font[i], "STCFN091");
332     }
333     else if (j==']')
334     {
335       R_SetPatchNum(&hu_font2[i], "DIG93");
336       R_SetPatchNum(&hu_font[i], "STCFN093");
337     }
338     else if (j<97)
339     {
340       sprintf(buffer, "STCFN%.3d",j);
341       R_SetPatchNum(&hu_font2[i], buffer);
342       R_SetPatchNum(&hu_font[i], buffer);
343       //jff 2/23/98 make all font chars defined, useful or not
344     }
345     else if (j>122)
346     {
347       sprintf(buffer, "STBR%.3d",j);
348       R_SetPatchNum(&hu_font2[i], buffer);
349       R_SetPatchNum(&hu_font[i], buffer);
350     }
351     else
352       hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap
353   }
354 
355   // CPhipps - load patches for message background
356   for (i=0; i<9; i++) {
357     sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]);
358     R_SetPatchNum(&hu_msgbg[i], buffer);
359   }
360 
361   // CPhipps - load patches for keys and double keys
362   for (i=0; i<6; i++) {
363     sprintf(buffer, "STKEYS%d", i);
364     R_SetPatchNum(&hu_fontk[i], buffer);
365   }
366 
367   R_SetSpriteByIndex(&hu_font_hud[4], SPR_MEDI);
368   R_SetSpriteByIndex(&hu_font_hud[5], SPR_ARM1);
369   R_SetSpriteByIndex(&hu_font_hud[6], SPR_ARM1);
370   R_SetSpriteByIndex(&hu_font_hud[7], SPR_ARM2);
371 
372   R_SetSpriteByIndex(&hu_font_hud[8], SPR_STIM);
373   R_SetSpriteByName(&hu_font_hud[9], "BON2A0");
374   R_SetSpriteByName(&hu_font_hud[10], "BON2B0");
375   R_SetSpriteByName(&hu_font_hud[11], "BON2D0");
376 
377   R_SetPatchNum(&hu_font_hud[12], "STTPRCNT");
378   R_SetPatchNum(&hu_font_hud[13], "STTPRCNT");
379 
380   R_SetPatchByName(&hu_font_hud[30], "HUDMED");
381   R_SetPatchByName(&hu_font_hud[31], "HUDARM1");
382   R_SetPatchByName(&hu_font_hud[32], "HUDARM1");
383   R_SetPatchByName(&hu_font_hud[33], "HUDARM2");
384 
385   R_SetSpriteByName(&hu_font_hud[40], "CLIPA0");
386   R_SetSpriteByName(&hu_font_hud[41], "SHELA0");
387   R_SetSpriteByName(&hu_font_hud[42], "CELLA0");
388   R_SetSpriteByName(&hu_font_hud[43], "ROCKA0");
389 
390 }
391 
392 //
393 // HU_Stop()
394 //
395 // Make the heads-up displays inactive
396 //
397 // Passed nothing, returns nothing
398 //
HU_Stop(void)399 static void HU_Stop(void)
400 {
401   headsupactive = false;
402 }
403 
404 //
405 // HU_Start(void)
406 //
407 // Create and initialize the heads-up widgets, software machines to
408 // maintain, update, and display information over the primary display
409 //
410 // This routine must be called after any change to the heads up configuration
411 // in order for the changes to take effect in the actual displays
412 //
413 // Passed nothing, returns nothing
414 //
HU_Start(void)415 void HU_Start(void)
416 {
417   int   i;
418   const char* s; /* cph - const */
419 
420   if (headsupactive)                    // stop before starting
421     HU_Stop();
422 
423   plr = &players[displayplayer];        // killough 3/7/98
424   message_on = false;
425   message_dontfuckwithme = false;
426   message_nottobefuckedwith = false;
427   chat_on = false;
428 
429   // create the message widget
430   // messages to player in upper-left of screen
431   HUlib_initSText
432   (
433     &w_message,
434     HU_MSGX,
435     HU_MSGY,
436     HU_MSGHEIGHT,
437     hu_font,
438     HU_FONTSTART,
439     hudcolor_mesg,
440     VPT_ALIGN_LEFT_TOP,
441     &message_on
442   );
443 
444   //jff 2/16/98 added some HUD widgets
445   // create the map title widget - map title display in lower left of automap
446   HUlib_initTextLine
447   (
448     &w_title,
449     HU_TITLEX,
450     HU_TITLEY,
451     hu_font,
452     HU_FONTSTART,
453     hudcolor_titl,
454     VPT_ALIGN_LEFT_BOTTOM
455   );
456 
457   // create the hud health widget
458   // bargraph and number for amount of health,
459   // lower left or upper right of screen
460   HUlib_initTextLine
461   (
462     &w_health,
463     0, 0,
464     hu_font2,
465     HU_FONTSTART,
466     CR_GREEN,
467     VPT_NONE
468   );
469 
470   HUlib_initTextLine
471   (
472     &w_health_big,
473     0, 0,
474     hu_font_hud,
475     HU_FONTSTART,
476     CR_RED,
477     VPT_NONE
478   );
479 
480   HUlib_initTextLine
481   (
482     &w_medict_icon_big,
483     0, 0,
484     hu_font_hud,
485     HU_FONTSTART,
486     CR_RED,
487     VPT_NONE
488   );
489 
490   HUlib_initTextLine
491   (
492     &w_medict_icon_small,
493     0, 0,
494     hu_font_hud,
495     HU_FONTSTART,
496     CR_RED,
497     VPT_NONE
498   );
499 
500   HUlib_initTextLine
501   (
502     &w_medict_icon_custom,
503     0, 0,
504     hu_font_hud,
505     HU_FONTSTART,
506     CR_RED,
507     VPT_NONE
508   );
509 
510   // create the hud armor widget
511   // bargraph and number for amount of armor,
512   // lower left or upper right of screen
513   HUlib_initTextLine
514   (
515     &w_armor,
516     0, 0,
517     hu_font2,
518     HU_FONTSTART,
519     CR_GREEN,
520     VPT_NONE
521   );
522 
523   HUlib_initTextLine
524   (
525     &w_armor_big,
526     0, 0,
527     hu_font_hud,
528     HU_FONTSTART,
529     CR_RED,
530     VPT_NONE
531   );
532 
533   HUlib_initTextLine
534   (
535     &w_armor_icon_big,
536     0, 0,
537     hu_font_hud,
538     HU_FONTSTART,
539     CR_RED,
540     VPT_NONE
541   );
542 
543   HUlib_initTextLine
544   (
545     &w_armor_icon_small,
546     0, 0,
547     hu_font_hud,
548     HU_FONTSTART,
549     CR_RED,
550     VPT_NONE
551   );
552 
553   HUlib_initTextLine
554   (
555     &w_armor_icon_custom,
556     0, 0,
557     hu_font_hud,
558     HU_FONTSTART,
559     CR_RED,
560     VPT_NONE
561   );
562 
563   // create the hud ammo widget
564   // bargraph and number for amount of ammo for current weapon,
565   // lower left or lower right of screen
566   HUlib_initTextLine
567   (
568     &w_ammo,
569     0, 0,
570     hu_font2,
571     HU_FONTSTART,
572     CR_GOLD,
573     VPT_NONE
574   );
575 
576   // create the hud weapons widget
577   // list of numbers of weapons possessed
578   // lower left or lower right of screen
579   HUlib_initTextLine
580   (
581     &w_weapon,
582     0, 0,
583     hu_font2,
584     HU_FONTSTART,
585     CR_GRAY,
586     VPT_NONE
587   );
588 
589   // create the hud keys widget
590   // display of key letters possessed
591   // lower left of screen
592   HUlib_initTextLine
593   (
594     &w_keys,
595     0, 0,
596     hu_font2,
597     HU_FONTSTART,
598     CR_GRAY,
599     VPT_NONE
600   );
601 
602   // create the hud graphic keys widget
603   // display of key graphics possessed
604   // lower left of screen
605   HUlib_initTextLine
606   (
607     &w_gkeys,
608     0, 0,
609     hu_fontk,
610     HU_FONTSTART,
611     CR_RED,
612     VPT_NONE
613   );
614 
615   // create the hud monster/secret widget
616   // totals and current values for kills, items, secrets
617   // lower left of screen
618   HUlib_initTextLine
619   (
620     &w_monsec,
621     0, 0,
622     hu_font2,
623     HU_FONTSTART,
624     CR_GRAY,
625     VPT_NONE
626   );
627 
628   HUlib_initTextLine
629   (
630     &w_medict_percent,
631     0, 0,
632     hu_font_hud,
633     HU_FONTSTART,
634     CR_GRAY,
635     VPT_NONE
636   );
637 
638   HUlib_initTextLine
639   (
640     &w_armor_percent,
641     0, 0,
642     hu_font_hud,
643     HU_FONTSTART,
644     CR_GRAY,
645     VPT_NONE
646   );
647 
648   HUlib_initTextLine
649   (
650     &w_ammo_big,
651     0, 0,
652     hu_font_hud,
653     HU_FONTSTART,
654     CR_RED,
655     VPT_NONE
656   );
657 
658   HUlib_initTextLine
659   (
660     &w_ammo_icon,
661     0, 0,
662     hu_font_hud,
663     HU_FONTSTART,
664     CR_RED,
665     VPT_NONE
666   );
667 
668   HUlib_initTextLine
669   (
670     &w_keys_icon,
671     0, 0,
672     hu_fontk,
673     HU_FONTSTART,
674     CR_RED,
675     VPT_NONE
676   );
677 
678   // create the hud text refresh widget
679   // scrolling display of last hud_msg_lines messages received
680   if (hud_msg_lines>HU_MAXMESSAGES)
681     hud_msg_lines=HU_MAXMESSAGES;
682   //jff 4/21/98 if setup has disabled message list while active, turn it off
683   message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways
684   //jff 2/26/98 add the text refresh widget initialization
685   HUlib_initMText
686   (
687     &w_rtext,
688     0,
689     0,
690     320,
691 //    SCREENWIDTH,
692     (hud_msg_lines+2)*HU_REFRESHSPACING,
693     hu_font,
694     HU_FONTSTART,
695     hudcolor_list,
696     hu_msgbg,
697     VPT_ALIGN_LEFT_TOP,
698     &message_list
699   );
700 
701   // initialize the automap's level title widget
702   // e6y: stop SEGV here when gamemap is not initialized
703   if (gamestate == GS_LEVEL && gamemap > 0) /* cph - stop SEGV here when not in level */
704   switch (gamemode)
705   {
706     case shareware:
707     case registered:
708     case retail:
709       s = HU_TITLE;
710       break;
711 
712     case commercial:
713     default:  // Ty 08/27/98 - modified to check mission for TNT/Plutonia
714       s = (gamemission==pack_tnt)  ? HU_TITLET :
715           (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2;
716       break;
717   } else s = "";
718   while (*s)
719     HUlib_addCharToTextLine(&w_title, *(s++));
720 
721   // create the automaps coordinate widget
722   // jff 3/3/98 split coord widget into three lines: x,y,z
723   // jff 2/16/98 added
724   HUlib_initTextLine
725   (
726     &w_coordx,
727     HU_COORDX,
728     HU_COORDX_Y,
729     hu_font,
730     HU_FONTSTART,
731     hudcolor_xyco,
732     VPT_ALIGN_RIGHT_TOP
733   );
734   HUlib_initTextLine
735   (
736     &w_coordy,
737     HU_COORDX,
738     HU_COORDY_Y,
739     hu_font,
740     HU_FONTSTART,
741     hudcolor_xyco,
742     VPT_ALIGN_RIGHT_TOP
743   );
744   HUlib_initTextLine
745   (
746     &w_coordz,
747     HU_COORDX,
748     HU_COORDZ_Y,
749     hu_font,
750     HU_FONTSTART,
751     hudcolor_xyco,
752     VPT_ALIGN_RIGHT_TOP
753   );
754 //e6y
755   HUlib_initTextLine
756   (
757     &w_map_monsters,
758     HU_MAP_STAT_X,
759     HU_MAP_MONSTERS_Y,
760     hu_font,
761     HU_FONTSTART,
762     hudcolor_mapstat_title,
763     VPT_ALIGN_LEFT_TOP
764   );
765   HUlib_initTextLine
766   (
767     &w_map_secrets,
768     HU_MAP_STAT_X,
769     HU_MAP_SECRETS_Y,
770     hu_font,
771     HU_FONTSTART,
772     hudcolor_mapstat_title,
773     VPT_ALIGN_LEFT_TOP
774   );
775   HUlib_initTextLine
776   (
777     &w_map_items,
778     HU_MAP_STAT_X,
779     HU_MAP_ITEMS_Y,
780     hu_font,
781     HU_FONTSTART,
782     hudcolor_mapstat_title,
783     VPT_ALIGN_LEFT_TOP
784   );
785   HUlib_initTextLine
786   (
787     &w_map_time,
788     HU_MAP_STAT_X,
789     HU_MAP_TIME_Y,
790     hu_font,
791     HU_FONTSTART,
792     hudcolor_mapstat_time,
793     VPT_ALIGN_LEFT_TOP
794   );
795   HUlib_initTextLine
796   (
797     &w_map_totaltime,
798     HU_MAP_STAT_X,
799     HU_MAP_TOTALTIME_Y,
800     hu_font,
801     HU_FONTSTART,
802     hudcolor_mapstat_time,
803     VPT_ALIGN_LEFT_TOP
804   );
805   HUlib_initTextLine
806   (
807     &w_hudadd,
808     0, 0,
809     hu_font2,
810     HU_FONTSTART,
811     CR_GRAY,
812     VPT_NONE
813   );
814   HUlib_initTextLine
815   (
816     &w_centermsg,
817     HU_CENTERMSGX,
818     HU_CENTERMSGY,
819     hu_font,
820     HU_FONTSTART,
821     hudcolor_titl,
822     VPT_STRETCH
823   );
824   HUlib_initTextLine
825   (
826     &w_precache,
827     16,
828     186,
829     hu_font,
830     HU_FONTSTART,
831     CR_RED,
832     VPT_ALIGN_LEFT_BOTTOM
833   );
834   strcpy(hud_add,"");
835   s = hud_add;
836   while (*s)
837     HUlib_addCharToTextLine(&w_hudadd, *(s++));
838 
839   for(i = 0; i < NUMTRACES; i++)
840   {
841     HUlib_initTextLine(
842       &w_traces[i],
843       HU_TRACERX,
844       HU_TRACERY+i*HU_GAPY,
845       hu_font2,
846       HU_FONTSTART,
847       CR_GRAY,
848       VPT_ALIGN_LEFT_BOTTOM
849     );
850 
851     strcpy(traces[i].hudstr, "");
852     s = traces[i].hudstr;
853     while (*s)
854       HUlib_addCharToTextLine(&w_traces[i], *(s++));
855     HUlib_drawTextLine(&w_traces[i], false);
856   }
857 
858 
859   //jff 2/16/98 initialize ammo widget
860   strcpy(hud_ammostr,"AMM ");
861 
862   //jff 2/16/98 initialize health widget
863   strcpy(hud_healthstr,"HEL ");
864 
865   //jff 2/16/98 initialize armor widget
866   strcpy(hud_armorstr,"ARM ");
867 
868   //jff 2/17/98 initialize weapons widget
869   strcpy(hud_weapstr,"WEA ");
870 
871   //jff 2/17/98 initialize keys widget
872   //jff 3/17/98 show frags in deathmatch mode
873   strcpy(hud_keysstr,(deathmatch ? "FRG " : "KEY "));
874 
875   //jff 2/17/98 initialize graphic keys widget
876   strcpy(hud_gkeysstr," ");
877 
878   //jff 2/17/98 initialize kills/items/secret widget
879   strcpy(hud_monsecstr,"STS ");
880 
881   // create the chat widget
882   HUlib_initIText
883   (
884     &w_chat,
885     HU_INPUTX,
886     HU_INPUTY,
887     hu_font,
888     HU_FONTSTART,
889     hudcolor_chat,
890     VPT_NONE,
891     &chat_on
892   );
893 
894   // create the inputbuffer widgets, one per player
895   for (i=0 ; i<MAXPLAYERS ; i++)
896     HUlib_initIText
897     (
898       &w_inputbuffer[i],
899       0,
900       0,
901       0,
902       0,
903       hudcolor_chat,
904       VPT_NONE,
905       &always_off
906     );
907 
908   // now allow the heads-up display to run
909   headsupactive = true;
910 
911   HU_LoadHUDDefs();
912 
913   HU_MoveHud(true);
914 }
915 
HU_NextHud(void)916 void HU_NextHud(void)
917 {
918   if (huds_count > 0)
919   {
920     hud_num = (hud_num + 1) % huds_count;    // cycle hud_active
921   }
922 }
923 
924 typedef void (*HU_widget_build_func)(void);
925 typedef void (*HU_widget_draw_func)(void);
926 
927 typedef struct hud_cfg_item_s
928 {
929   char name[80];
930   int x;
931   int y;
932 } hud_cfg_item_t;
933 
934 typedef struct hud_widget_s
935 {
936   hu_textline_t *hu_textline;
937   int x;
938   int y;
939   enum patch_translation_e flags;
940   HU_widget_build_func build;
941   HU_widget_draw_func draw;
942   const char *name;
943 } hud_widget_t;
944 
945 typedef struct hud_widgets_list_s
946 {
947   int count;
948   hud_widget_t *items;
949 } hud_widgets_list_t;
950 
951 int huds_count;
952 hud_widgets_list_t *huds;
953 hud_widgets_list_t *hud_current;
954 
955 void HU_widget_build_ammo(void);
956 void HU_widget_draw_ammo(void);
957 void HU_widget_build_weapon(void);
958 void HU_widget_draw_weapon(void);
959 void HU_widget_build_keys(void);
960 void HU_widget_draw_keys(void);
961 void HU_widget_build_monsec(void);
962 void HU_widget_draw_monsec(void);
963 void HU_widget_build_health(void);
964 void HU_widget_draw_health(void);
965 void HU_widget_build_armor(void);
966 void HU_widget_draw_armor(void);
967 void HU_widget_build_hudadd(void);
968 void HU_widget_draw_hudadd(void);
969 
970 void HU_widget_build_health_big(void);
971 void HU_widget_draw_health_big(void);
972 void HU_widget_build_armor_big(void);
973 void HU_widget_draw_armor_big(void);
974 
975 void HU_widget_build_medict_icon_big(void);
976 void HU_widget_draw_medict_icon_big(void);
977 void HU_widget_build_armor_icon_big(void);
978 void HU_widget_draw_armor_icon_big(void);
979 
980 void HU_widget_build_medict_icon_small(void);
981 void HU_widget_draw_medict_icon_small(void);
982 void HU_widget_build_armor_icon_small(void);
983 void HU_widget_draw_armor_icon_small(void);
984 
985 void HU_widget_build_medict_icon_custom(void);
986 void HU_widget_draw_medict_icon_custom(void);
987 void HU_widget_build_armor_icon_custom(void);
988 void HU_widget_draw_armor_icon_custom(void);
989 
990 void HU_widget_build_medict_percent(void);
991 void HU_widget_draw_medict_percent(void);
992 void HU_widget_build_armor_percent(void);
993 void HU_widget_draw_armor_percent(void);
994 
995 void HU_widget_build_ammo_big(void);
996 void HU_widget_draw_ammo_big(void);
997 void HU_widget_build_ammo_icon(void);
998 void HU_widget_draw_ammo_icon(void);
999 
1000 void HU_widget_build_gkeys(void);
1001 void HU_widget_draw_gkeys(void);
1002 
1003 static hud_widget_t hud_name_widget[] =
1004 {
1005   {&w_ammo,   0, 0, 0, HU_widget_build_ammo,   HU_widget_draw_ammo,   "ammo"},
1006   {&w_weapon, 0, 0, 0, HU_widget_build_weapon, HU_widget_draw_weapon, "weapon"},
1007   {&w_keys,   0, 0, 0, HU_widget_build_keys,   HU_widget_draw_keys,   "keys"},
1008   {&w_monsec, 0, 0, 0, HU_widget_build_monsec, HU_widget_draw_monsec, "monsec"},
1009   {&w_health, 0, 0, 0, HU_widget_build_health, HU_widget_draw_health, "health"},
1010   {&w_armor,  0, 0, 0, HU_widget_build_armor,  HU_widget_draw_armor,  "armor"},
1011   {&w_hudadd, 0, 0, 0, HU_widget_build_hudadd, HU_widget_draw_hudadd, "hudadd"},
1012 
1013   {&w_keys_icon, 0, 0, 0, HU_widget_build_gkeys, HU_widget_draw_gkeys, "gkeys"},
1014 
1015   {&w_traces[0], 0, 0, 0, NULL, NULL, "tracers"},
1016 
1017   {&w_health_big, 0, 0, VPT_NOOFFSET, HU_widget_build_health_big, HU_widget_draw_health_big, "health_big"},
1018   {&w_armor_big,  0, 0, VPT_NOOFFSET, HU_widget_build_armor_big,  HU_widget_draw_armor_big,  "armor_big"},
1019 
1020   {&w_medict_icon_big, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_big, HU_widget_draw_medict_icon_big, "medict_icon_big"},
1021   {&w_armor_icon_big,  0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_big,  HU_widget_draw_armor_icon_big,  "armor_icon_big"},
1022 
1023   {&w_medict_icon_small, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_small, HU_widget_draw_medict_icon_small, "medict_icon_small"},
1024   {&w_armor_icon_small,  0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_small,  HU_widget_draw_armor_icon_small,  "armor_icon_small"},
1025 
1026   {&w_medict_icon_custom, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_custom, HU_widget_draw_medict_icon_custom, "medict_icon_custom"},
1027   {&w_armor_icon_custom,  0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_custom,  HU_widget_draw_armor_icon_custom,  "armor_icon_custom"},
1028 
1029   {&w_medict_percent, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_percent, HU_widget_draw_medict_percent, "medict_percent"},
1030   {&w_armor_percent,  0, 0, VPT_NOOFFSET, HU_widget_build_armor_percent,  HU_widget_draw_armor_percent,  "armor_percent"},
1031 
1032   {&w_ammo_big,  0, 0, VPT_NOOFFSET, HU_widget_build_ammo_big,  HU_widget_draw_ammo_big,  "ammo_big"},
1033   {&w_ammo_big,  0, 0, VPT_NOOFFSET, HU_widget_build_ammo_big,  HU_widget_draw_ammo_big,  "ammo_big"},
1034   {&w_ammo_icon, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_icon, HU_widget_draw_ammo_icon, "ammo_icon"},
1035   {&w_ammo_icon, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_icon, HU_widget_draw_ammo_icon, "ammo_icon"},
1036 
1037   {NULL, 0, 0, 0, NULL, NULL, NULL}
1038 };
1039 
HU_LoadHUDDefs(void)1040 void HU_LoadHUDDefs(void)
1041 {
1042   static int init = 0;
1043 
1044   int lump, i, params_count;
1045   hud_cfg_item_t cfg_item;
1046   hud_widgets_list_t *list = NULL;
1047   char st[200];
1048 
1049   if (init)
1050     return;
1051 
1052   init = true;
1053 
1054   huds_count = 0;
1055   huds = NULL;
1056 
1057   lump = (W_CheckNumForName)("-PRBHUD-", ns_prboom);
1058   if (lump != -1)
1059   {
1060     SC_OpenLumpByNum(lump);
1061 
1062     // Get actor class name.
1063     while (SC_GetString())
1064     {
1065       // declaration of hud
1066       if (SC_Compare("hud"))
1067       {
1068         // skip everything after "hud" signature
1069         while (SC_Check())
1070           SC_GetString();
1071 
1072         // setup new hud
1073         huds_count++;
1074         huds = realloc(huds, huds_count * sizeof(huds[0]));
1075         list = &huds[huds_count - 1];
1076         list->items = NULL;
1077         list->count = 0;
1078 
1079         // definition of hud is below
1080         continue;
1081       }
1082 
1083       // keep going until a valid HUD declaration has been found
1084       if (huds_count < 1)
1085         continue;
1086 
1087       strncpy(st, sc_String, sizeof(st) - 1);
1088 
1089       while (SC_Check() && SC_GetString())
1090       {
1091         strncat(st, " ", sizeof(st) - 1);
1092         strncat(st, sc_String, sizeof(st) - 1);
1093       }
1094       st[sizeof(st) - 1] = 0;
1095 
1096       // hud_widget x y
1097       params_count = sscanf(st, "%s %d %d", &cfg_item.name[0], &cfg_item.x, &cfg_item.y);
1098       if (params_count == 3)
1099       {
1100         for (i = 0; hud_name_widget[i].name; i++)
1101         {
1102           if (!strcasecmp(hud_name_widget[i].name, cfg_item.name))
1103           {
1104             hud_widget_t *item;
1105 
1106             list->count++;
1107             list->items = realloc(list->items, list->count * sizeof(list->items[0]));
1108 
1109             item = &list->items[list->count - 1];
1110 
1111             item->hu_textline = hud_name_widget[i].hu_textline;
1112 
1113             item->x = cfg_item.x;
1114             item->y = cfg_item.y;
1115 
1116             if (abs(cfg_item.x) < 160)
1117             {
1118               item->flags = (abs(cfg_item.y) > 100 ? VPT_ALIGN_LEFT_BOTTOM : VPT_ALIGN_LEFT_TOP);
1119             }
1120             else
1121             {
1122               item->flags = (abs(cfg_item.y) > 100 ? VPT_ALIGN_RIGHT_BOTTOM : VPT_ALIGN_RIGHT_TOP);
1123             }
1124             item->flags |= hud_name_widget[i].flags;
1125 
1126             item->build = hud_name_widget[i].build;
1127             item->draw = hud_name_widget[i].draw;
1128 
1129             break;
1130           }
1131         }
1132       }
1133     }
1134 
1135     SC_Close();
1136   }
1137 }
1138 
1139 //
1140 // HU_MoveHud()
1141 //
1142 // Move the HUD display from distributed to compact mode or vice-versa
1143 //
1144 // Passed nothing, returns nothing
1145 //
1146 //jff 3/9/98 create this externally callable to avoid glitch
1147 // when menu scatter's HUD due to delay in change of position
1148 //
1149 
HU_MoveHud(int force)1150 void HU_MoveHud(int force)
1151 {
1152   static int ohud_num = -1;
1153 
1154   //jff 3/4/98 move displays around on F5 changing hud_distributed
1155   if ((huds_count > 0) && (force || hud_num != ohud_num))
1156   {
1157     int i;
1158 
1159     hud_current = &huds[hud_num % huds_count];
1160 
1161     for (i = 0; i < hud_current->count; i++)
1162     {
1163       hud_current->items[i].hu_textline->x = hud_current->items[i].x;
1164       hud_current->items[i].hu_textline->y = hud_current->items[i].y;
1165       hud_current->items[i].hu_textline->flags = hud_current->items[i].flags;
1166     }
1167 
1168     ohud_num = hud_num;
1169   }
1170 }
1171 
HU_GetHealthColor(int health,int def)1172 int HU_GetHealthColor(int health, int def)
1173 {
1174   int result;
1175 
1176   if (health < health_red)
1177     result = CR_RED;
1178   else if (health < health_yellow)
1179     result = CR_GOLD;
1180   else if (health <= health_green)
1181     result = CR_GREEN;
1182   else
1183     result = def;
1184 
1185   return result;
1186 }
1187 
HU_GetArmorColor(int armor,int def)1188 int HU_GetArmorColor(int armor, int def)
1189 {
1190   int result;
1191 
1192   if (armor < armor_red)
1193     result = CR_RED;
1194   else if (armor < armor_yellow)
1195     result = CR_GOLD;
1196   else if (armor <= armor_green)
1197     result = CR_GREEN;
1198   else
1199     result = def;
1200 
1201   return result;
1202 }
1203 
HU_GetAmmoColor(int ammo,int fullammo)1204 int HU_GetAmmoColor(int ammo, int fullammo)
1205 {
1206   int result;
1207 
1208   int ammopct = (100 * ammo) / fullammo;
1209 
1210   if (ammopct < ammo_red)
1211     result = CR_RED;
1212   else if (ammopct < ammo_yellow)
1213     result = CR_GOLD;
1214   else
1215     result = CR_GREEN;
1216 
1217   return result;
1218 }
1219 
HU_widget_build_ammo(void)1220 void HU_widget_build_ammo(void)
1221 {
1222   int i;
1223   char *s;
1224   char ammostr[80];  //jff 3/8/98 allow plenty room for dehacked mods
1225   int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo];
1226 
1227   // do the hud ammo display
1228   // clear the widgets internal line
1229   HUlib_clearTextLine(&w_ammo);
1230   strcpy(hud_ammostr,"AMM ");
1231   if (weaponinfo[plr->readyweapon].ammo == am_noammo || fullammo == 0)
1232   { // special case for weapon with no ammo selected - blank bargraph + N/A
1233     strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A");
1234     w_ammo.cm = CR_GRAY;
1235   }
1236   else
1237   {
1238     int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo];
1239     int ammopct = (100*ammo)/fullammo;
1240     int ammobars = ammopct/4;
1241 
1242     // build the numeric amount init string
1243     sprintf(ammostr,"%d/%d",ammo,fullammo);
1244     // build the bargraph string
1245     // full bargraph chars
1246     for (i=4;i<4+ammobars/4;)
1247       hud_ammostr[i++] = 123;
1248     // plus one last character with 0,1,2,3 bars
1249     switch(ammobars%4)
1250     {
1251     case 0:
1252       break;
1253     case 1:
1254       hud_ammostr[i++] = 126;
1255       break;
1256     case 2:
1257       hud_ammostr[i++] = 125;
1258       break;
1259     case 3:
1260       hud_ammostr[i++] = 124;
1261       break;
1262     }
1263 
1264     // pad string with blank bar characters
1265     while(i<4+7)
1266       hud_ammostr[i++] = 127;
1267     hud_ammostr[i] = '\0';
1268     strcat(hud_ammostr,ammostr);
1269 
1270     // set the display color from the percentage of total ammo held
1271     w_ammo.cm = HU_GetAmmoColor(ammo, fullammo);
1272   }
1273   // transfer the init string to the widget
1274   s = hud_ammostr;
1275   while (*s)
1276     HUlib_addCharToTextLine(&w_ammo, *(s++));
1277 }
1278 
HU_widget_draw_ammo(void)1279 void HU_widget_draw_ammo(void)
1280 {
1281   // display the ammo widget every frame
1282   HUlib_drawTextLine(&w_ammo, false);
1283 }
1284 
HU_widget_build_health(void)1285 void HU_widget_build_health(void)
1286 {
1287   int i;
1288   char *s;
1289   char healthstr[80];//jff
1290   int health = plr->health;
1291   int healthbars = health>100? 25 : health/4;
1292 
1293   if (w_health.val != -1 && w_health.val == health)
1294     return;
1295   w_health.val = health;
1296 
1297   // clear the widgets internal line
1298   HUlib_clearTextLine(&w_health);
1299 
1300   // build the numeric amount init string
1301   sprintf(healthstr,"%3d",health);
1302   // build the bargraph string
1303   // full bargraph chars
1304   for (i=4;i<4+healthbars/4;)
1305     hud_healthstr[i++] = 123;
1306   // plus one last character with 0,1,2,3 bars
1307   switch(healthbars%4)
1308   {
1309   case 0:
1310     break;
1311   case 1:
1312     hud_healthstr[i++] = 126;
1313     break;
1314   case 2:
1315     hud_healthstr[i++] = 125;
1316     break;
1317   case 3:
1318     hud_healthstr[i++] = 124;
1319     break;
1320   }
1321   // pad string with blank bar characters
1322   while(i<4+7)
1323     hud_healthstr[i++] = 127;
1324   hud_healthstr[i] = '\0';
1325   strcat(hud_healthstr,healthstr);
1326 
1327   // set the display color from the amount of health posessed
1328   w_health.cm = HU_GetHealthColor(health, CR_BLUE);
1329 
1330   // transfer the init string to the widget
1331   s = hud_healthstr;
1332   while (*s)
1333     HUlib_addCharToTextLine(&w_health, *(s++));
1334 }
1335 
HU_widget_draw_health(void)1336 void HU_widget_draw_health(void)
1337 {
1338   HUlib_drawTextLine(&w_health, false);
1339 }
1340 
HU_widget_build_health_big(void)1341 void HU_widget_build_health_big(void)
1342 {
1343   char *s;
1344   char healthstr[80];//jff
1345   int health = plr->health;
1346 
1347   if (w_health_big.val != -1 && w_health_big.val == health)
1348     return;
1349   w_health_big.val = health;
1350 
1351   // clear the widgets internal line
1352   HUlib_clearTextLine(&w_health_big);
1353 
1354   // build the numeric amount init string
1355   sprintf(healthstr,"%d",health);
1356 
1357   // set the display color from the amount of health posessed
1358   if (!sts_always_red)
1359     w_health_big.cm = HU_GetHealthColor(health, CR_BLUE2);
1360 
1361   // transfer the init string to the widget
1362   s = healthstr;
1363   while (*s)
1364     HUlib_addCharToTextLine(&w_health_big, *(s++));
1365 }
1366 
HU_widget_draw_health_big(void)1367 void HU_widget_draw_health_big(void)
1368 {
1369   HUlib_drawTextLine(&w_health_big, false);
1370 }
1371 
HU_widget_build_medict_icon_big(void)1372 void HU_widget_build_medict_icon_big(void)
1373 {
1374   // transfer the graphic key text to the widget
1375   HUlib_clearTextLine(&w_medict_icon_big);
1376   HUlib_addCharToTextLine(&w_medict_icon_big, '!' + 0 + 4);
1377 }
1378 
HU_widget_draw_medict_icon_big(void)1379 void HU_widget_draw_medict_icon_big(void)
1380 {
1381   HUlib_drawTextLine(&w_medict_icon_big, false);
1382 }
1383 
HU_widget_build_medict_icon_small(void)1384 void HU_widget_build_medict_icon_small(void)
1385 {
1386   // transfer the graphic key text to the widget
1387   HUlib_clearTextLine(&w_medict_icon_small);
1388   HUlib_addCharToTextLine(&w_medict_icon_small, '!' + 0 + 8);
1389 }
1390 
HU_widget_draw_medict_icon_small(void)1391 void HU_widget_draw_medict_icon_small(void)
1392 {
1393   HUlib_drawTextLine(&w_medict_icon_small, false);
1394 }
1395 
HU_widget_build_medict_icon_custom(void)1396 void HU_widget_build_medict_icon_custom(void)
1397 {
1398   // transfer the graphic key text to the widget
1399   HUlib_clearTextLine(&w_medict_icon_custom);
1400   HUlib_addCharToTextLine(&w_medict_icon_custom, '!' + 0 + 30);
1401 }
1402 
HU_widget_draw_medict_icon_custom(void)1403 void HU_widget_draw_medict_icon_custom(void)
1404 {
1405   HUlib_drawTextLine(&w_medict_icon_custom, false);
1406 }
1407 
HU_widget_build_armor_icon_custom(void)1408 void HU_widget_build_armor_icon_custom(void)
1409 {
1410   // transfer the graphic key text to the widget
1411   HUlib_clearTextLine(&w_armor_icon_custom);
1412   HUlib_addCharToTextLine(&w_armor_icon_custom, (char)('!' + plr->armortype + 1 + 30));
1413 }
1414 
HU_widget_draw_armor_icon_custom(void)1415 void HU_widget_draw_armor_icon_custom(void)
1416 {
1417   HUlib_drawTextLine(&w_armor_icon_custom, false);
1418 }
1419 
HU_widget_build_armor(void)1420 void HU_widget_build_armor(void)
1421 {
1422   int i;
1423   char *s;
1424   char armorstr[80]; //jff
1425   int armor = plr->armorpoints;
1426   int armorbars = armor>100? 25 : armor/4;
1427 
1428   if (w_armor.val != -1 && w_armor.val == armor)
1429     return;
1430   w_armor.val = armor;
1431 
1432   // clear the widgets internal line
1433   HUlib_clearTextLine(&w_armor);
1434   // build the numeric amount init string
1435   sprintf(armorstr,"%3d",armor);
1436   // build the bargraph string
1437   // full bargraph chars
1438   for (i=4;i<4+armorbars/4;)
1439     hud_armorstr[i++] = 123;
1440   // plus one last character with 0,1,2,3 bars
1441   switch(armorbars%4)
1442   {
1443   case 0:
1444     break;
1445   case 1:
1446     hud_armorstr[i++] = 126;
1447     break;
1448   case 2:
1449     hud_armorstr[i++] = 125;
1450     break;
1451   case 3:
1452     hud_armorstr[i++] = 124;
1453     break;
1454   }
1455   // pad string with blank bar characters
1456   while(i<4+7)
1457     hud_armorstr[i++] = 127;
1458   hud_armorstr[i] = '\0';
1459   strcat(hud_armorstr,armorstr);
1460 
1461   // set the display color from the amount of armor posessed
1462   w_armor.cm = HU_GetArmorColor(armor, CR_BLUE);
1463 
1464   // transfer the init string to the widget
1465   s = hud_armorstr;
1466   while (*s)
1467     HUlib_addCharToTextLine(&w_armor, *(s++));
1468 }
1469 
HU_widget_draw_armor(void)1470 void HU_widget_draw_armor(void)
1471 {
1472   HUlib_drawTextLine(&w_armor, false);
1473 }
1474 
HU_widget_build_armor_big(void)1475 void HU_widget_build_armor_big(void)
1476 {
1477   char *s;
1478   char armorstr[80]; //jff
1479   int armor = plr->armorpoints;
1480 
1481   if (w_armor_big.val != -1 && w_armor_big.val == armor)
1482     return;
1483   w_armor_big.val = armor;
1484 
1485   // clear the widgets internal line
1486   HUlib_clearTextLine(&w_armor_big);
1487   // build the numeric amount init string
1488   sprintf(armorstr,"%d",armor);
1489 
1490   // set the display color from the amount of armor posessed
1491   if (!sts_always_red)
1492     w_armor_big.cm = HU_GetArmorColor(armor, CR_BLUE2);
1493 
1494   // transfer the init string to the widget
1495   s = armorstr;
1496   while (*s)
1497     HUlib_addCharToTextLine(&w_armor_big, *(s++));
1498 }
1499 
HU_widget_draw_armor_big(void)1500 void HU_widget_draw_armor_big(void)
1501 {
1502   HUlib_drawTextLine(&w_armor_big, false);
1503 }
1504 
HU_widget_build_armor_icon_big(void)1505 void HU_widget_build_armor_icon_big(void)
1506 {
1507   // transfer the graphic key text to the widget
1508   HUlib_clearTextLine(&w_armor_icon_big);
1509   HUlib_addCharToTextLine(&w_armor_icon_big, (char)('!' + plr->armortype + 1 + 4));
1510 }
1511 
HU_widget_draw_armor_icon_big(void)1512 void HU_widget_draw_armor_icon_big(void)
1513 {
1514   HUlib_drawTextLine(&w_armor_icon_big, false);
1515 }
1516 
HU_widget_build_armor_icon_small(void)1517 void HU_widget_build_armor_icon_small(void)
1518 {
1519   // transfer the graphic key text to the widget
1520   HUlib_clearTextLine(&w_armor_icon_small);
1521   HUlib_addCharToTextLine(&w_armor_icon_small, (char)('!' + plr->armortype + 1 + 8));
1522 }
1523 
HU_widget_draw_armor_icon_small(void)1524 void HU_widget_draw_armor_icon_small(void)
1525 {
1526   HUlib_drawTextLine(&w_armor_icon_small, false);
1527 }
1528 
1529 
HU_widget_build_weapon(void)1530 void HU_widget_build_weapon(void)
1531 {
1532   int i;
1533   char *s;
1534   int w;
1535   int ammo,fullammo,ammopct;
1536 
1537   // clear the widgets internal line
1538   HUlib_clearTextLine(&w_weapon);
1539   i=4; hud_weapstr[i] = '\0';      //jff 3/7/98 make sure ammo goes away
1540 
1541   // do each weapon that exists in current gamemode
1542   for (w=0;w<=wp_supershotgun;w++) //jff 3/4/98 show fists too, why not?
1543   {
1544     int ok=1;
1545     //jff avoid executing for weapons that do not exist
1546     switch (gamemode)
1547     {
1548     case shareware:
1549       if (w>=wp_plasma && w!=wp_chainsaw)
1550         ok=0;
1551       break;
1552     case retail:
1553     case registered:
1554       if (w>=wp_supershotgun)
1555         ok=0;
1556       break;
1557     default:
1558     case commercial:
1559       break;
1560     }
1561     if (!ok) continue;
1562 
1563     ammo = plr->ammo[weaponinfo[w].ammo];
1564     fullammo = plr->maxammo[weaponinfo[w].ammo];
1565     ammopct=0;
1566 
1567     // skip weapons not currently posessed
1568     if (!plr->weaponowned[w])
1569       continue;
1570 
1571     ammopct = fullammo? (100*ammo)/fullammo : 100;
1572 
1573     // display each weapon number in a color related to the ammo for it
1574     hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1575     if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD
1576       hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY;
1577     else if (ammopct<ammo_red)
1578       hud_weapstr[i++] = '0'+CR_RED;
1579     else if (ammopct<ammo_yellow)
1580       hud_weapstr[i++] = '0'+CR_GOLD;
1581     else
1582       hud_weapstr[i++] = '0'+CR_GREEN;
1583     hud_weapstr[i++] = '0'+w+1;
1584     hud_weapstr[i++] = ' ';
1585     hud_weapstr[i] = '\0';
1586   }
1587 
1588   // transfer the init string to the widget
1589   s = hud_weapstr;
1590   while (*s)
1591     HUlib_addCharToTextLine(&w_weapon, *(s++));
1592 }
1593 
HU_widget_draw_weapon(void)1594 void HU_widget_draw_weapon(void)
1595 {
1596   HUlib_drawTextLine(&w_weapon, false);
1597 }
1598 
HU_widget_build_keys(void)1599 void HU_widget_build_keys(void)
1600 {
1601   int i;
1602   int k;
1603   char *s;
1604 
1605   hud_keysstr[4] = '\0';    //jff 3/7/98 make sure deleted keys go away
1606   //jff add case for graphic key display
1607   if (!deathmatch)
1608   {
1609     i=0;
1610     hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string
1611     // build text string whose characters call out graphic keys from fontk
1612     for (k=0;k<6;k++)
1613     {
1614       // skip keys not possessed
1615       if (!plr->cards[k])
1616         continue;
1617 
1618       hud_gkeysstr[i++] = '!'+k;   // key number plus '!' is char for key
1619       hud_gkeysstr[i++] = ' ';     // spacing
1620       hud_gkeysstr[i++] = ' ';
1621     }
1622     hud_gkeysstr[i]='\0';
1623   }
1624   else // not possible in current code, unless deathmatching,
1625   {
1626     i=4;
1627     hud_keysstr[i] = '\0';  //jff 3/7/98 make sure deleted keys go away
1628 
1629     // if deathmatch, build string showing top four frag counts
1630     if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch
1631     {
1632       int top1=-999,top2=-999,top3=-999,top4=-999;
1633       int idx1=-1,idx2=-1,idx3=-1,idx4=-1;
1634       int fragcount,m;
1635       char numbuf[32];
1636 
1637       // scan thru players
1638       for (k=0;k<MAXPLAYERS;k++)
1639       {
1640         // skip players not in game
1641         if (!playeringame[k])
1642           continue;
1643 
1644         fragcount = 0;
1645         // compute number of times they've fragged each player
1646         // minus number of times they've been fragged by them
1647         for (m=0;m<MAXPLAYERS;m++)
1648         {
1649           if (!playeringame[m]) continue;
1650           fragcount += (m!=k)?  players[k].frags[m] : -players[k].frags[m];
1651         }
1652 
1653         // very primitive sort of frags to find top four
1654         if (fragcount>top1)
1655         {
1656           top4=top3; top3=top2; top2 = top1; top1=fragcount;
1657           idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k;
1658         }
1659         else if (fragcount>top2)
1660         {
1661           top4=top3; top3=top2; top2=fragcount;
1662           idx4=idx3; idx3=idx2; idx2=k;
1663         }
1664         else if (fragcount>top3)
1665         {
1666           top4=top3; top3=fragcount;
1667           idx4=idx3; idx3=k;
1668         }
1669         else if (fragcount>top4)
1670         {
1671           top4=fragcount;
1672           idx4=k;
1673         }
1674       }
1675       // if the biggest number exists, put it in the init string
1676       if (idx1>-1)
1677       {
1678         sprintf(numbuf,"%5d",top1);
1679         // make frag count in player's color via escape code
1680         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1681         hud_keysstr[i++] = '0'+plyrcoltran[idx1&3];
1682         s = numbuf;
1683         while (*s)
1684           hud_keysstr[i++] = *(s++);
1685       }
1686       // if the second biggest number exists, put it in the init string
1687       if (idx2>-1)
1688       {
1689         sprintf(numbuf,"%5d",top2);
1690         // make frag count in player's color via escape code
1691         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1692         hud_keysstr[i++] = '0'+plyrcoltran[idx2&3];
1693         s = numbuf;
1694         while (*s)
1695           hud_keysstr[i++] = *(s++);
1696       }
1697       // if the third biggest number exists, put it in the init string
1698       if (idx3>-1)
1699       {
1700         sprintf(numbuf,"%5d",top3);
1701         // make frag count in player's color via escape code
1702         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1703         hud_keysstr[i++] = '0'+plyrcoltran[idx3&3];
1704         s = numbuf;
1705         while (*s)
1706           hud_keysstr[i++] = *(s++);
1707       }
1708       // if the fourth biggest number exists, put it in the init string
1709       if (idx4>-1)
1710       {
1711         sprintf(numbuf,"%5d",top4);
1712         // make frag count in player's color via escape code
1713         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1714         hud_keysstr[i++] = '0'+plyrcoltran[idx4&3];
1715         s = numbuf;
1716         while (*s)
1717           hud_keysstr[i++] = *(s++);
1718       }
1719       hud_keysstr[i] = '\0';
1720     } //jff 3/17/98 end of deathmatch clause
1721     else // build alphabetical key display (not used currently)
1722     {
1723       // scan the keys
1724       for (k=0;k<6;k++)
1725       {
1726         // skip any not possessed by the displayed player's stats
1727         if (!plr->cards[k])
1728           continue;
1729 
1730         // use color escapes to make text in key's color
1731         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1732         switch(k)
1733         {
1734         case 0:
1735           hud_keysstr[i++] = '0'+CR_BLUE;
1736           hud_keysstr[i++] = 'B';
1737           hud_keysstr[i++] = 'C';
1738           hud_keysstr[i++] = ' ';
1739           break;
1740         case 1:
1741           hud_keysstr[i++] = '0'+CR_GOLD;
1742           hud_keysstr[i++] = 'Y';
1743           hud_keysstr[i++] = 'C';
1744           hud_keysstr[i++] = ' ';
1745           break;
1746         case 2:
1747           hud_keysstr[i++] = '0'+CR_RED;
1748           hud_keysstr[i++] = 'R';
1749           hud_keysstr[i++] = 'C';
1750           hud_keysstr[i++] = ' ';
1751           break;
1752         case 3:
1753           hud_keysstr[i++] = '0'+CR_BLUE;
1754           hud_keysstr[i++] = 'B';
1755           hud_keysstr[i++] = 'S';
1756           hud_keysstr[i++] = ' ';
1757           break;
1758         case 4:
1759           hud_keysstr[i++] = '0'+CR_GOLD;
1760           hud_keysstr[i++] = 'Y';
1761           hud_keysstr[i++] = 'S';
1762           hud_keysstr[i++] = ' ';
1763           break;
1764         case 5:
1765           hud_keysstr[i++] = '0'+CR_RED;
1766           hud_keysstr[i++] = 'R';
1767           hud_keysstr[i++] = 'S';
1768           hud_keysstr[i++] = ' ';
1769           break;
1770         }
1771         hud_keysstr[i]='\0';
1772       }
1773     }
1774   }
1775 
1776   HUlib_clearTextLine(&w_keys);      // clear the widget strings
1777 
1778   // transfer the built string (frags or key title) to the widget
1779   s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags
1780   while (*s)
1781     HUlib_addCharToTextLine(&w_keys, *(s++));
1782 
1783   //jff 3/17/98 show graphic keys in non-DM only
1784   if (!deathmatch) //jff 3/7/98 display graphic keys
1785   {
1786     // clear the widget strings
1787     HUlib_clearTextLine(&w_gkeys);
1788     // transfer the graphic key text to the widget
1789     s = hud_gkeysstr;
1790     while (*s)
1791       HUlib_addCharToTextLine(&w_gkeys, *(s++));
1792   }
1793 
1794   w_gkeys.x = w_keys.x + 20;
1795   w_gkeys.y = w_keys.y;
1796   w_gkeys.flags = w_keys.flags;
1797 }
1798 
HU_widget_draw_keys(void)1799 void HU_widget_draw_keys(void)
1800 {
1801   HUlib_drawTextLine(&w_keys, false);
1802   if (!deathmatch)
1803   {
1804     HUlib_drawTextLine(&w_gkeys, false);
1805   }
1806 }
1807 
HU_widget_build_monsec(void)1808 void HU_widget_build_monsec(void)
1809 {
1810   int i;
1811   char *s;
1812 
1813   //e6y
1814   char allkills[200], allsecrets[200];
1815   int playerscount;
1816   int  fullkillcount, fullitemcount, fullsecretcount;
1817   int color, killcolor, itemcolor, secretcolor;
1818 
1819   // clear the internal widget text buffer
1820   HUlib_clearTextLine(&w_monsec);
1821   if (!hudadd_smarttotals || deathmatch)
1822   {
1823     sprintf
1824       (
1825       hud_monsecstr,
1826       "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d",
1827       plr->killcount,totallive,
1828       plr->itemcount,totalitems,
1829       plr->secretcount,totalsecret
1830       );
1831   }
1832   else
1833   {
1834     int allkills_len = 0;
1835     int allsecrets_len = 0;
1836 
1837     playerscount = 0;
1838     fullkillcount = 0;
1839     fullitemcount = 0;
1840     fullsecretcount = 0;
1841     for (i=0 ; i<MAXPLAYERS ; i++)
1842     {
1843       if (playeringame[i])
1844       {
1845         color = i==displayplayer?0x33:0x32;
1846         if (playerscount==0)
1847         {
1848           allkills_len = sprintf(allkills, "\x1b%c%d", color, players[i].killcount - players[i].resurectedkillcount);
1849           allsecrets_len = sprintf(allsecrets, "\x1b%c%d", color, players[i].secretcount);
1850         }
1851         else
1852         {
1853           if (allkills_len >= 0 && allsecrets_len >=0)
1854           {
1855             allkills_len += sprintf(&allkills[allkills_len], "\x1b%c+%d", color, players[i].killcount - players[i].resurectedkillcount);
1856             allsecrets_len += sprintf(&allsecrets[allsecrets_len], "\x1b%c+%d", color, players[i].secretcount);
1857           }
1858         }
1859         playerscount++;
1860         fullkillcount += players[i].killcount - players[i].resurectedkillcount;
1861         fullitemcount += players[i].itemcount;
1862         fullsecretcount += players[i].secretcount;
1863       }
1864     }
1865     killcolor = (fullkillcount >= totalkills ? 0x37 : 0x35);
1866     secretcolor = (fullsecretcount >= totalsecret ? 0x37 : 0x35);
1867     itemcolor = (fullitemcount >= totalitems ? 0x37 : 0x35);
1868     if (playerscount<2)
1869     {
1870       sprintf
1871         (
1872         hud_monsecstr,
1873         "STS \x1b\x36K \x1b%c%d/%d \x1b\x36I \x1b%c%d/%d \x1b\x36S \x1b%c%d/%d",
1874         killcolor, fullkillcount,totalkills,
1875         itemcolor,plr->itemcount,totalitems,
1876         secretcolor, fullsecretcount,totalsecret
1877         );
1878     }
1879     else
1880     {
1881       sprintf
1882         (
1883         hud_monsecstr,
1884         "STS \x1b\x36K %s \x1b%c%d/%d \x1b\x36I \x1b%c%d/%d \x1b\x36S %s \x1b%c%d/%d",
1885         allkills,killcolor,fullkillcount,totalkills,
1886         itemcolor,plr->itemcount,totalitems,
1887         allsecrets,secretcolor,fullsecretcount,totalsecret
1888         );
1889     }
1890   }
1891 
1892   // transfer the init string to the widget
1893   s = hud_monsecstr;
1894   while (*s)
1895     HUlib_addCharToTextLine(&w_monsec, *(s++));
1896 }
1897 
HU_widget_draw_monsec(void)1898 void HU_widget_draw_monsec(void)
1899 {
1900   HUlib_drawTextLine(&w_monsec, false);
1901 }
1902 
HU_widget_build_hudadd(void)1903 void HU_widget_build_hudadd(void)
1904 {
1905   char *s;
1906   hud_add[0] = 0;
1907 
1908   if (!hudadd_gamespeed && !hudadd_leveltime)
1909     return;
1910 
1911   if (hudadd_gamespeed)
1912     sprintf(hud_add,"\x1b\x32speed \x1b\x33%.2d ", realtic_clock_rate);
1913   if ((hudadd_leveltime) || (demoplayback && hudadd_demotime))
1914   {
1915     static char demo_len_null[1]={0};
1916     char *demo_len = demoplayback && hudadd_demotime ? demo_len_st : demo_len_null;
1917     if (totalleveltimes)
1918       sprintf(hud_add+strlen(hud_add),"\x1b\x32time \x1b\x35%d:%02d%s \x1b\x33%d:%05.2f ",
1919       (totalleveltimes+leveltime)/35/60, ((totalleveltimes+leveltime)%(60*35))/35, demo_len,
1920       leveltime/35/60, (float)(leveltime%(60*35))/35);
1921     else
1922       sprintf(hud_add+strlen(hud_add),"\x1b\x32time \x1b\x33%d:%05.2f%s ",
1923       leveltime/35/60, (float)(leveltime%(60*35))/35, demo_len);
1924   }
1925   HUlib_clearTextLine(&w_hudadd);
1926   s = hud_add;
1927   while (*s)
1928     HUlib_addCharToTextLine(&w_hudadd, *(s++));
1929 }
1930 
HU_widget_draw_hudadd(void)1931 void HU_widget_draw_hudadd(void)
1932 {
1933   if (hudadd_gamespeed || hudadd_leveltime)
1934   {
1935     HUlib_drawTextLine(&w_hudadd, false);
1936   }
1937 }
1938 
HU_widget_build_medict_percent(void)1939 void HU_widget_build_medict_percent(void)
1940 {
1941   int health = plr->health;
1942 
1943   if (w_medict_percent.val != -1 && w_medict_percent.val == health)
1944     return;
1945   w_medict_percent.val = health;
1946 
1947   // transfer the graphic key text to the widget
1948   HUlib_clearTextLine(&w_medict_percent);
1949 
1950   if (!sts_always_red)
1951   {
1952     if (sts_pct_always_gray)
1953       w_medict_percent.cm = CR_GRAY;
1954     else
1955       w_medict_percent.cm = HU_GetHealthColor(health, CR_BLUE2);
1956   }
1957 
1958   HUlib_addCharToTextLine(&w_medict_percent, (char)('!' + 12));
1959 }
1960 
HU_widget_draw_medict_percent(void)1961 void HU_widget_draw_medict_percent(void)
1962 {
1963   HUlib_drawTextLine(&w_medict_percent, false);
1964 }
1965 
HU_widget_build_armor_percent(void)1966 void HU_widget_build_armor_percent(void)
1967 {
1968   int armor = plr->armorpoints;
1969 
1970   if (w_armor_percent.val != -1 && w_armor_percent.val == armor)
1971     return;
1972   w_armor_percent.val = armor;
1973 
1974   // transfer the graphic key text to the widget
1975   HUlib_clearTextLine(&w_armor_percent);
1976 
1977   if (!sts_always_red)
1978   {
1979     if (sts_pct_always_gray)
1980       w_armor_percent.cm = CR_GRAY;
1981     else
1982       w_armor_percent.cm = HU_GetArmorColor(armor, CR_BLUE2);
1983   }
1984 
1985   HUlib_addCharToTextLine(&w_armor_percent, (char)('!' + 13));
1986 }
1987 
HU_widget_draw_armor_percent(void)1988 void HU_widget_draw_armor_percent(void)
1989 {
1990   HUlib_drawTextLine(&w_armor_percent, false);
1991 }
1992 
HU_widget_build_ammo_big(void)1993 void HU_widget_build_ammo_big(void)
1994 {
1995   char *s;
1996   char ammostr[80];
1997   int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo];
1998 
1999   // clear the widgets internal line
2000   HUlib_clearTextLine(&w_ammo_big);
2001 
2002   if (weaponinfo[plr->readyweapon].ammo != am_noammo && fullammo != 0)
2003   {
2004     int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo];
2005 
2006     // build the numeric amount init string
2007     sprintf(ammostr, "%d", ammo);
2008 
2009     // set the display color from the percentage of total ammo held
2010     if (!sts_always_red)
2011       w_ammo_big.cm = HU_GetAmmoColor(ammo, fullammo);
2012 
2013     // transfer the init string to the widget
2014     s = ammostr;
2015     while (*s)
2016       HUlib_addCharToTextLine(&w_ammo_big, *(s++));
2017   }
2018 }
2019 
HU_widget_draw_ammo_big(void)2020 void HU_widget_draw_ammo_big(void)
2021 {
2022   HUlib_drawTextLine(&w_ammo_big, false);
2023 }
2024 
HU_widget_build_ammo_icon(void)2025 void HU_widget_build_ammo_icon(void)
2026 {
2027   int ammo = weaponinfo[plr->readyweapon].ammo;
2028 
2029   if (w_ammo_icon.val != -1 && w_ammo_icon.val == ammo)
2030     return;
2031   w_ammo_icon.val = ammo;
2032 
2033   if (ammo < NUMAMMO)
2034   {
2035     HUlib_clearTextLine(&w_ammo_icon);
2036     HUlib_addCharToTextLine(&w_ammo_icon, (char)('!' + ammo + 40));
2037   }
2038   else
2039   {
2040     HUlib_clearTextLine(&w_ammo_icon);
2041   }
2042 }
2043 
HU_widget_draw_ammo_icon(void)2044 void HU_widget_draw_ammo_icon(void)
2045 {
2046   HUlib_drawTextLine(&w_ammo_icon, false);
2047 }
2048 
HU_widget_build_gkeys(void)2049 void HU_widget_build_gkeys(void)
2050 {
2051   int i, k;
2052   char *s;
2053   char gkeysstr[80];
2054   int mask = 0;
2055 
2056   // build text string whose characters call out graphic keys from fontk
2057   i = 0;
2058   for (k = 0; k < 6; k++)
2059   {
2060     // skip keys not possessed
2061     if (!plr->cards[k])
2062       continue;
2063 
2064     gkeysstr[i++] = '!' + k; // key number plus '!' is char for key
2065     gkeysstr[i++] = ' ';     // spacing
2066     gkeysstr[i++] = ' ';
2067 
2068     mask |= (1 << k);
2069   }
2070 
2071   if (w_keys_icon.val != -1 && w_keys_icon.val == mask)
2072     return;
2073   w_keys_icon.val = mask;
2074 
2075   gkeysstr[i] = '\0';
2076   while (((--i) > 0) && (gkeysstr[i] == ' '))
2077     gkeysstr[i] = '\0';
2078 
2079   // clear the widget strings
2080   HUlib_clearTextLine(&w_keys_icon);
2081   // transfer the graphic key text to the widget
2082   s = gkeysstr;
2083   while (*s)
2084     HUlib_addCharToTextLine(&w_keys_icon, *(s++));
2085 
2086 }
2087 
HU_widget_draw_gkeys(void)2088 void HU_widget_draw_gkeys(void)
2089 {
2090   HUlib_drawTextLine(&w_keys_icon, false);
2091 }
2092 
2093 //
2094 // HU_Drawer()
2095 //
2096 // Draw all the pieces of the heads-up display
2097 //
2098 // Passed nothing, returns nothing
2099 //
HU_Drawer(void)2100 void HU_Drawer(void)
2101 {
2102   char *s;
2103   player_t *plr;
2104   //jff 3/4/98 speed update up for slow systems
2105   //e6y: speed update for uncapped framerate
2106   static dboolean needupdate = false;
2107   if (realframe) needupdate = !needupdate;
2108 
2109   // don't draw anything if there's a fullscreen menu up
2110   if (menuactive == mnact_full)
2111     return;
2112 
2113   plr = &players[displayplayer];         // killough 3/7/98
2114   // draw the automap widgets if automap is displayed
2115   if (automapmode & am_active)
2116   {
2117     if (!(automapmode & am_overlay) || (viewheight != SCREENHEIGHT))//!hud_displayed)
2118     {
2119       // map title
2120       HUlib_drawTextLine(&w_title, false);
2121     }
2122 
2123     //jff 2/16/98 output new coord display
2124     // x-coord
2125     if (map_point_coordinates)
2126     {
2127 
2128       //e6y: speedup
2129       if (!realframe)
2130       {
2131         HUlib_drawTextLine(&w_coordx, false);
2132         HUlib_drawTextLine(&w_coordy, false);
2133         HUlib_drawTextLine(&w_coordz, false);
2134       }
2135       else
2136       {
2137         sprintf(hud_coordstrx,"X: %-5d", (plr->mo->x)>>FRACBITS);
2138         HUlib_clearTextLine(&w_coordx);
2139         s = hud_coordstrx;
2140         while (*s)
2141           HUlib_addCharToTextLine(&w_coordx, *(s++));
2142         HUlib_drawTextLine(&w_coordx, false);
2143 
2144         //jff 3/3/98 split coord display into x,y,z lines
2145         // y-coord
2146         sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS);
2147         HUlib_clearTextLine(&w_coordy);
2148         s = hud_coordstry;
2149         while (*s)
2150           HUlib_addCharToTextLine(&w_coordy, *(s++));
2151         HUlib_drawTextLine(&w_coordy, false);
2152 
2153         //jff 3/3/98 split coord display into x,y,z lines
2154         //jff 2/22/98 added z
2155         // z-coord
2156         sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS);
2157         HUlib_clearTextLine(&w_coordz);
2158         s = hud_coordstrz;
2159         while (*s)
2160           HUlib_addCharToTextLine(&w_coordz, *(s++));
2161         HUlib_drawTextLine(&w_coordz, false);
2162       }
2163     }
2164 
2165     if (map_level_stat)
2166     {
2167       static char str[32];
2168       int time = leveltime / TICRATE;
2169       int ttime = (totalleveltimes + leveltime) / TICRATE;
2170 
2171       sprintf(str, "Monsters: \x1b%c%d/%d", '0' + hudcolor_mapstat_value,
2172         players[consoleplayer].killcount - players[consoleplayer].resurectedkillcount,
2173         totalkills);
2174       HUlib_clearTextLine(&w_map_monsters);
2175       s = str;
2176       while (*s)
2177         HUlib_addCharToTextLine(&w_map_monsters, *(s++));
2178       HUlib_drawTextLine(&w_map_monsters, false);
2179 
2180       sprintf(str, "Secrets: \x1b%c%d/%d", '0' + hudcolor_mapstat_value,
2181         players[consoleplayer].secretcount, totalsecret);
2182       HUlib_clearTextLine(&w_map_secrets);
2183       s = str;
2184       while (*s)
2185         HUlib_addCharToTextLine(&w_map_secrets, *(s++));
2186       HUlib_drawTextLine(&w_map_secrets, false);
2187 
2188       sprintf(str, "Items: \x1b%c%d/%d", '0' + hudcolor_mapstat_value,
2189         players[consoleplayer].itemcount, totalitems);
2190       HUlib_clearTextLine(&w_map_items);
2191       s = str;
2192       while (*s)
2193         HUlib_addCharToTextLine(&w_map_items, *(s++));
2194       HUlib_drawTextLine(&w_map_items, false);
2195 
2196       sprintf(str, "%02d:%02d:%02d", time/3600, (time%3600)/60, time%60);
2197       HUlib_clearTextLine(&w_map_time);
2198       s = str;
2199       while (*s)
2200         HUlib_addCharToTextLine(&w_map_time, *(s++));
2201       HUlib_drawTextLine(&w_map_time, false);
2202 
2203       if (totalleveltimes > 0)
2204       {
2205         sprintf(str, "%02d:%02d:%02d", ttime/3600, (ttime%3600)/60, ttime%60);
2206         HUlib_clearTextLine(&w_map_totaltime);
2207         s = str;
2208         while (*s)
2209           HUlib_addCharToTextLine(&w_map_totaltime, *(s++));
2210         HUlib_drawTextLine(&w_map_totaltime, false);
2211       }
2212     }
2213   }
2214 
2215   // draw the weapon/health/ammo/armor/kills/keys displays if optioned
2216   //jff 2/17/98 allow new hud stuff to be turned off
2217   // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY
2218   if
2219   (
2220     hud_num > 0 &&                   // hud optioned on
2221     hud_displayed &&                 // hud on from fullscreen key
2222     viewheight==SCREENHEIGHT &&      // fullscreen mode is active
2223     (!(automapmode & am_active) ||   // automap is not active
2224      (automapmode & am_overlay))
2225   )
2226   {
2227     int i;
2228 
2229     HU_MoveHud(false);                  // insure HUD display coords are correct
2230 
2231     if (hud_current)
2232     {
2233       for (i = 0; i < hud_current->count; i++)
2234       {
2235         if (hud_current->items[i].build && hud_current->items[i].draw)
2236         {
2237           if (realframe)
2238           {
2239             hud_current->items[i].build();
2240           }
2241           hud_current->items[i].draw();
2242         }
2243       }
2244     }
2245 
2246     //e6y
2247     if (traces_present)
2248     {
2249       int k, num = 0;
2250       for(k = 0; k < NUMTRACES; k++)
2251       {
2252         if (traces[k].count)
2253         {
2254           if (realframe)
2255           {
2256             w_traces[num].y = w_traces[0].y - num * 8;
2257 
2258             if (traces[k].ApplyFunc)
2259               traces[k].ApplyFunc(k);
2260 
2261             HUlib_clearTextLine(&w_traces[num]);
2262             s = traces[k].hudstr;
2263             while (*s)
2264               HUlib_addCharToTextLine(&w_traces[num], *(s++));
2265 
2266             if (traces[k].ResetFunc)
2267               traces[k].ResetFunc(k);
2268           }
2269           HUlib_drawTextLine(&w_traces[num], false);
2270           num++;
2271         }
2272       }
2273     }
2274 
2275   }
2276 
2277   //jff 3/4/98 display last to give priority
2278   HU_Erase(); // jff 4/24/98 Erase current lines before drawing current
2279               // needed when screen not fullsize
2280 
2281   //jff 4/21/98 if setup has disabled message list while active, turn it off
2282   if (hud_msg_lines<=1)
2283     message_list = false;
2284 
2285   // if the message review not enabled, show the standard message widget
2286   if (!message_list)
2287     HUlib_drawSText(&w_message);
2288 
2289   //e6y
2290   if (messagecenter_counter)
2291     HUlib_drawTextLine(&w_centermsg, false);
2292 
2293   // if the message review is enabled show the scrolling message review
2294   if (hud_msg_lines>1 && message_list)
2295     HUlib_drawMText(&w_rtext);
2296 
2297   // display the interactive buffer for chat entry
2298   HUlib_drawIText(&w_chat);
2299 }
2300 
2301 //
2302 // HU_Erase()
2303 //
2304 // Erase hud display lines that can be trashed by small screen display
2305 //
2306 // Passed nothing, returns nothing
2307 //
HU_Erase(void)2308 void HU_Erase(void)
2309 {
2310   // erase the message display or the message review display
2311   if (!message_list)
2312     HUlib_eraseSText(&w_message);
2313   else
2314     HUlib_eraseMText(&w_rtext);
2315 
2316   //e6y
2317   if (messagecenter_counter)
2318     HUlib_eraseTextLine(&w_centermsg);
2319 
2320   // erase the interactive text buffer for chat entry
2321   HUlib_eraseIText(&w_chat);
2322 
2323   // erase the automap title
2324   HUlib_eraseTextLine(&w_title);
2325 }
2326 
2327 //
2328 // HU_Ticker()
2329 //
2330 // Update the hud displays once per frame
2331 //
2332 // Passed nothing, returns nothing
2333 //
2334 static dboolean bsdown; // Is backspace down?
2335 static int bscounter;
2336 
HU_Ticker(void)2337 void HU_Ticker(void)
2338 {
2339   int i, rc;
2340   char c;
2341 
2342   // tick down message counter if message is up
2343   if (message_counter && !--message_counter)
2344   {
2345     message_on = false;
2346     message_nottobefuckedwith = false;
2347   }
2348   if (bsdown && bscounter++ > 9) {
2349     HUlib_keyInIText(&w_chat, (unsigned char)key_backspace);
2350     bscounter = 8;
2351   }
2352 
2353   // if messages on, or "Messages Off" is being displayed
2354   // this allows the notification of turning messages off to be seen
2355   if (showMessages || message_dontfuckwithme)
2356   {
2357     // display message if necessary
2358     if ((plr->message && !message_nottobefuckedwith)
2359         || (plr->message && message_dontfuckwithme))
2360     {
2361       //post the message to the message widget
2362       HUlib_addMessageToSText(&w_message, 0, plr->message);
2363       //jff 2/26/98 add message to refresh text widget too
2364       HUlib_addMessageToMText(&w_rtext, 0, plr->message);
2365 
2366       // clear the message to avoid posting multiple times
2367       plr->message = 0;
2368       // note a message is displayed
2369       message_on = true;
2370       // start the message persistence counter
2371       message_counter = HU_MSGTIMEOUT;
2372       // transfer "Messages Off" exception to the "being displayed" variable
2373       message_nottobefuckedwith = message_dontfuckwithme;
2374       // clear the flag that "Messages Off" is being posted
2375       message_dontfuckwithme = 0;
2376     }
2377   }
2378   //e6y
2379   if (messagecenter_counter)
2380     messagecenter_counter--;
2381   if (/*showMessages && */plr->centermessage)
2382   {
2383     const char *s = plr->centermessage;
2384     HUlib_clearTextLine(&w_centermsg);
2385     while (*s)
2386     {
2387       HUlib_addCharToTextLine(&w_centermsg, *(s++));
2388     }
2389     HUlib_setTextXCenter(&w_centermsg);
2390     plr->centermessage = NULL;
2391     messagecenter_counter = HU_MSGCENTERTIMEOUT;
2392 
2393     S_StartSound(NULL, sfx_secret);
2394   }
2395 
2396   // check for incoming chat characters
2397   if (netgame)
2398   {
2399     for (i=0; i<MAXPLAYERS; i++)
2400     {
2401       if (!playeringame[i])
2402         continue;
2403       if (i != consoleplayer
2404           && (c = players[i].cmd.chatchar))
2405       {
2406         if (c <= HU_BROADCAST)
2407           chat_dest[i] = c;
2408         else
2409         {
2410           if (c >= 'a' && c <= 'z')
2411             c = (char) shiftxform[(unsigned char) c];
2412           rc = HUlib_keyInIText(&w_inputbuffer[i], c);
2413           if (rc && c == KEYD_ENTER)
2414           {
2415             if (w_inputbuffer[i].l.len
2416                 && (chat_dest[i] == consoleplayer+1
2417                 || chat_dest[i] == HU_BROADCAST))
2418             {
2419               HUlib_addMessageToSText(&w_message,
2420                                       player_names[i],
2421                                       w_inputbuffer[i].l.l);
2422 
2423               message_nottobefuckedwith = true;
2424               message_on = true;
2425               message_counter = HU_MSGTIMEOUT;
2426               if ( gamemode == commercial )
2427                 S_StartSound(0, sfx_radio);
2428               else
2429                 S_StartSound(0, sfx_tink);
2430             }
2431             HUlib_resetIText(&w_inputbuffer[i]);
2432           }
2433         }
2434         players[i].cmd.chatchar = 0;
2435       }
2436     }
2437   }
2438 }
2439 
2440 #define QUEUESIZE   128
2441 
2442 static char chatchars[QUEUESIZE];
2443 static int  head = 0;
2444 static int  tail = 0;
2445 
2446 //
2447 // HU_queueChatChar()
2448 //
2449 // Add an incoming character to the circular chat queue
2450 //
2451 // Passed the character to queue, returns nothing
2452 //
HU_queueChatChar(char c)2453 static void HU_queueChatChar(char c)
2454 {
2455   if (((head + 1) & (QUEUESIZE-1)) == tail)
2456   {
2457     plr->message = HUSTR_MSGU;
2458   }
2459   else
2460   {
2461     chatchars[head] = c;
2462     head = (head + 1) & (QUEUESIZE-1);
2463   }
2464 }
2465 
2466 //
2467 // HU_dequeueChatChar()
2468 //
2469 // Remove the earliest added character from the circular chat queue
2470 //
2471 // Passed nothing, returns the character dequeued
2472 //
HU_dequeueChatChar(void)2473 char HU_dequeueChatChar(void)
2474 {
2475   char c;
2476 
2477   if (head != tail)
2478   {
2479     c = chatchars[tail];
2480     tail = (tail + 1) & (QUEUESIZE-1);
2481   }
2482   else
2483   {
2484     c = 0;
2485   }
2486   return c;
2487 }
2488 
2489 //
2490 // HU_Responder()
2491 //
2492 // Responds to input events that affect the heads up displays
2493 //
2494 // Passed the event to respond to, returns true if the event was handled
2495 //
HU_Responder(event_t * ev)2496 dboolean HU_Responder(event_t *ev)
2497 {
2498 
2499   static char   lastmessage[HU_MAXLINELENGTH+1];
2500   const char*   macromessage; // CPhipps - const char*
2501   dboolean   eatkey = false;
2502   static dboolean  shiftdown = false;
2503   static dboolean  altdown = false;
2504   unsigned char   c;
2505   int     i;
2506   int     numplayers;
2507 
2508   static int    num_nobrainers = 0;
2509 
2510   numplayers = 0;
2511   for (i=0 ; i<MAXPLAYERS ; i++)
2512     numplayers += playeringame[i];
2513 
2514   if (ev->data1 == key_shift)
2515   {
2516     shiftdown = ev->type == ev_keydown;
2517     return false;
2518   }
2519   else if (ev->data1 == key_alt)
2520   {
2521     altdown = ev->type == ev_keydown;
2522     return false;
2523   }
2524   else if (ev->data1 == key_backspace)
2525   {
2526     bsdown = ev->type == ev_keydown;
2527     bscounter = 0;
2528   }
2529 
2530   if (ev->type != ev_keydown)
2531     return false;
2532 
2533   if (!chat_on)
2534   {
2535     if (ev->data1 == key_enter)                                 // phares
2536     {
2537 #ifndef INSTRUMENTED  // never turn on message review if INSTRUMENTED defined
2538       if (hud_msg_lines>1)  // it posts multi-line messages that will trash
2539       {
2540         if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages
2541         message_list = !message_list; //jff 2/26/98 toggle list of messages
2542       }
2543 #endif
2544       if (!message_list)              // if not message list, refresh message
2545       {
2546         message_on = true;
2547         message_counter = HU_MSGTIMEOUT;
2548       }
2549       eatkey = true;
2550     }//jff 2/26/98 no chat if message review is displayed
2551     // killough 10/02/98: no chat if demo playback
2552     // no chat in -solo-net mode
2553     else if (!demoplayback && !message_list && netgame && numplayers > 1)
2554     {
2555       if (ev->data1 == key_chat)
2556     {
2557       eatkey = chat_on = true;
2558       HUlib_resetIText(&w_chat);
2559       HU_queueChatChar(HU_BROADCAST);
2560     }
2561     else if (numplayers > 2)
2562     {
2563       for (i=0; i<MAXPLAYERS ; i++)
2564       {
2565         if (ev->data1 == destination_keys[i])
2566         {
2567           if (playeringame[i] && i!=consoleplayer)
2568           {
2569             eatkey = chat_on = true;
2570             HUlib_resetIText(&w_chat);
2571             HU_queueChatChar((char)(i+1));
2572             break;
2573           }
2574           else if (i == consoleplayer)
2575           {
2576             num_nobrainers++;
2577             if (num_nobrainers < 3)
2578                 plr->message = HUSTR_TALKTOSELF1;
2579             else if (num_nobrainers < 6)
2580                 plr->message = HUSTR_TALKTOSELF2;
2581             else if (num_nobrainers < 9)
2582                 plr->message = HUSTR_TALKTOSELF3;
2583             else if (num_nobrainers < 32)
2584                 plr->message = HUSTR_TALKTOSELF4;
2585             else
2586                 plr->message = HUSTR_TALKTOSELF5;
2587           }
2588         }
2589       }
2590     }
2591     }
2592   }//jff 2/26/98 no chat functions if message review is displayed
2593   else if (!message_list)
2594   {
2595     c = ev->data1;
2596     // send a macro
2597     if (altdown)
2598     {
2599       c = c - '0';
2600       if (c > 9)
2601         return false;
2602       macromessage = chat_macros[c];
2603 
2604       // kill last message with a '\n'
2605         HU_queueChatChar((char)key_enter); // DEBUG!!!                // phares
2606 
2607       // send the macro message
2608       while (*macromessage)
2609         HU_queueChatChar(*macromessage++);
2610       HU_queueChatChar((char)key_enter);                            // phares
2611 
2612       // leave chat mode and notify that it was sent
2613       chat_on = false;
2614       strcpy(lastmessage, chat_macros[c]);
2615       plr->message = lastmessage;
2616       eatkey = true;
2617     }
2618     else
2619     {
2620       if (shiftdown || (c >= 'a' && c <= 'z'))
2621         c = shiftxform[c];
2622       eatkey = HUlib_keyInIText(&w_chat, c);
2623       if (eatkey)
2624         HU_queueChatChar(c);
2625 
2626       if (c == key_enter)                                     // phares
2627       {
2628         chat_on = false;
2629         if (w_chat.l.len)
2630         {
2631           strcpy(lastmessage, w_chat.l.l);
2632           plr->message = lastmessage;
2633         }
2634       }
2635       else if (c == key_escape)                               // phares
2636         chat_on = false;
2637     }
2638   }
2639   return eatkey;
2640 }
2641