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 "st_stuff.h" /* jff 2/16/98 need loc of status bar */
40 #include "w_wad.h"
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 
48 // global heads up display controls
49 
50 int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics
51 hud_mode_t hud_mode;
52 dbool   hud_showstats;   /* show secrets/items/kills stats */
53 dbool   hud_showkeys;    /* show keys HUD line */
54 dbool   hud_showweapons; /* show weapons HUD line */
55 
56 //
57 // Locally used constants, shortcuts.
58 //
59 // Ty 03/28/98 -
60 // These four shortcuts modifed to reflect char ** of mapnamesx[]
61 #define HU_TITLE  (*mapnames[(gameepisode-1)*9+gamemap-1])
62 #define HU_TITLE2 (*mapnames2[gamemap-1])
63 #define HU_TITLEP (*mapnamesp[gamemap-1])
64 #define HU_TITLET (*mapnamest[gamemap-1])
65 #define HU_TITLEHEIGHT  1
66 #define HU_TITLEX 0
67 //jff 2/16/98 change 167 to ST_Y-1
68 // CPhipps - changed to ST_TY
69 // proff - changed to 200-ST_HEIGHT for stretching
70 #define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height)
71 
72 //jff 2/16/98 add coord text widget coordinates
73 // proff - changed to SCREENWIDTH to 320 for stretching
74 #define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width)
75 //jff 3/3/98 split coord widget into three lines in upper right of screen
76 #define HU_COORDX_Y (1 + 0*hu_font['A'-HU_FONTSTART].height)
77 #define HU_COORDY_Y (2 + 1*hu_font['A'-HU_FONTSTART].height)
78 #define HU_COORDZ_Y (3 + 2*hu_font['A'-HU_FONTSTART].height)
79 
80 //jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap
81 #define HU_GAPY 8
82 #define HU_HUDHEIGHT (6*HU_GAPY)
83 #define HU_HUDX 2
84 #define HU_HUDY (200-HU_HUDHEIGHT-1)
85 #define HU_MONSECX (HU_HUDX)
86 #define HU_MONSECY (HU_HUDY+0*HU_GAPY)
87 #define HU_KEYSX   (HU_HUDX)
88 //jff 3/7/98 add offset for graphic key widget
89 #define HU_KEYSGX  (HU_HUDX+4*hu_font2['A'-HU_FONTSTART].width)
90 #define HU_KEYSY   (HU_HUDY+1*HU_GAPY)
91 #define HU_WEAPX   (HU_HUDX)
92 #define HU_WEAPY   (HU_HUDY+2*HU_GAPY)
93 #define HU_AMMOX   (HU_HUDX)
94 #define HU_AMMOY   (HU_HUDY+3*HU_GAPY)
95 #define HU_HEALTHX (HU_HUDX)
96 #define HU_HEALTHY (HU_HUDY+4*HU_GAPY)
97 #define HU_ARMORX  (HU_HUDX)
98 #define HU_ARMORY  (HU_HUDY+5*HU_GAPY)
99 
100 //jff 3/4/98 distributed HUD positions
101 #define HU_HUDX_LL 2
102 #define HU_HUDY_LL (200-2*HU_GAPY-1)
103 // proff/nicolas 09/20/98: Changed for high-res
104 #define HU_HUDX_LR (320-120)
105 #define HU_HUDY_LR (200-2*HU_GAPY-1)
106 // proff/nicolas 09/20/98: Changed for high-res
107 #define HU_HUDX_UR (320-15*8)
108 #define HU_HUDY_UR 2
109 #define HU_MONSECX_D (HU_HUDX_UR)
110 #define HU_MONSECY_D (HU_HUDY_UR+0*HU_GAPY)
111 #define HU_KEYSX_D   (HU_HUDX_UR)
112 #define HU_KEYSGX_D  (HU_HUDX_UR+4*hu_font2['A'-HU_FONTSTART].width)
113 #define HU_KEYSY_D   (HU_HUDY_UR+1*HU_GAPY)
114 #define HU_WEAPX_D   (HU_HUDX_LR)
115 #define HU_WEAPY_D   (HU_HUDY_LR+0*HU_GAPY)
116 #define HU_AMMOX_D   (HU_HUDX_LR)
117 #define HU_AMMOY_D   (HU_HUDY_LR+1*HU_GAPY)
118 #define HU_HEALTHX_D (HU_HUDX_LL)
119 #define HU_HEALTHY_D (HU_HUDY_LL+0*HU_GAPY)
120 #define HU_ARMORX_D  (HU_HUDX_LL)
121 #define HU_ARMORY_D  (HU_HUDY_LL+1*HU_GAPY)
122 
123 //#define HU_INPUTTOGGLE  't' // not used                           // phares
124 #define HU_INPUTX HU_MSGX
125 #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1)
126 #define HU_INPUTWIDTH 64
127 #define HU_INPUTHEIGHT  1
128 
129 #define key_alt KEYD_RALT
130 #define key_shift KEYD_RSHIFT
131 
132 const char* chat_macros[] =
133 // Ty 03/27/98 - *not* externalized
134 // CPhipps - const char*
135 {
136   HUSTR_CHATMACRO0,
137   HUSTR_CHATMACRO1,
138   HUSTR_CHATMACRO2,
139   HUSTR_CHATMACRO3,
140   HUSTR_CHATMACRO4,
141   HUSTR_CHATMACRO5,
142   HUSTR_CHATMACRO6,
143   HUSTR_CHATMACRO7,
144   HUSTR_CHATMACRO8,
145   HUSTR_CHATMACRO9
146 };
147 
148 const char* player_names[] =
149 // Ty 03/27/98 - *not* externalized
150 // CPhipps - const char*
151 {
152   HUSTR_PLRGREEN,
153   HUSTR_PLRINDIGO,
154   HUSTR_PLRBROWN,
155   HUSTR_PLRRED
156 };
157 
158 //jff 3/17/98 translate player colmap to text color ranges
159 int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED};
160 
161 char chat_char;                 // remove later.
162 static player_t*  plr;
163 
164 // font sets
165 patchnum_t hu_font[HU_FONTSIZE];
166 patchnum_t hu_font2[HU_FONTSIZE];
167 patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators
168 patchnum_t hu_msgbg[9];          //jff 2/26/98 add patches for message background
169 
170 // widgets
171 static hu_textline_t  w_title;
172 static hu_stext_t     w_message;
173 static hu_itext_t     w_chat;
174 static hu_itext_t     w_inputbuffer[MAXPLAYERS];
175 static hu_textline_t  w_coordx; //jff 2/16/98 new coord widget for automap
176 static hu_textline_t  w_coordy; //jff 3/3/98 split coord widgets automap
177 static hu_textline_t  w_coordz; //jff 3/3/98 split coord widgets automap
178 static hu_textline_t  w_ammo;   //jff 2/16/98 new ammo widget for hud
179 static hu_textline_t  w_health; //jff 2/16/98 new health widget for hud
180 static hu_textline_t  w_armor;  //jff 2/16/98 new armor widget for hud
181 static hu_textline_t  w_weapon; //jff 2/16/98 new weapon widget for hud
182 static hu_textline_t  w_keys;   //jff 2/16/98 new keys widget for hud
183 static hu_textline_t  w_gkeys;  //jff 3/7/98 graphic keys widget for hud
184 static hu_textline_t  w_monsec; //jff 2/16/98 new kill/secret widget for hud
185 static hu_mtext_t     w_rtext;  //jff 2/26/98 text message refresh widget
186 
187 static dbool    always_off = FALSE;
188 static char       chat_dest[MAXPLAYERS];
189 dbool           chat_on;
190 static dbool    message_on;
191 static dbool    message_list; //2/26/98 enable showing list of messages
192 dbool           message_dontfuckwithme;
193 static dbool    message_nottobefuckedwith;
194 static int        message_counter;
195 extern int        showMessages;
196 extern dbool    automapactive;
197 static dbool    headsupactive = FALSE;
198 
199 //jff 2/16/98 hud supported automap colors added
200 int hudcolor_titl;  // color range of automap level title
201 int hudcolor_xyco;  // color range of new coords on automap
202 //jff 2/16/98 hud text colors, controls added
203 int hudcolor_mesg;  // color range of scrolling messages
204 int hudcolor_chat;  // color range of chat lines
205 int hud_msg_lines;  // number of message lines in window
206 //jff 2/26/98 hud text colors, controls added
207 int hudcolor_list;  // list of messages color
208 int hud_list_bgon;  // enable for solid window background for message list
209 
210 //jff 2/16/98 initialization strings for ammo, health, armor widgets
211 static char hud_coordstrx[32];
212 static char hud_coordstry[32];
213 static char hud_coordstrz[32];
214 static char hud_ammostr[80];
215 static char hud_healthstr[80];
216 static char hud_armorstr[80];
217 static char hud_weapstr[80];
218 static char hud_keysstr[80];
219 static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display
220 static char hud_monsecstr[80];
221 
222 //
223 // Builtin map names.
224 // The actual names can be found in DStrings.h.
225 //
226 // Ty 03/27/98 - externalized map name arrays - now in d_deh.c
227 // and converted to arrays of pointers to char *
228 // See modified HUTITLEx macros
229 extern char **mapnames[];
230 extern char **mapnames2[];
231 extern char **mapnamesp[];
232 extern char **mapnamest[];
233 
234 extern int map_point_coordinates;
235 
236 // key tables
237 // jff 5/10/98 french support removed,
238 // as it was not being used and couldn't be easily tested
239 //
240 const char* shiftxform;
241 
242 const char english_shiftxform[] =
243 {
244   0,
245   1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
246   11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
247   21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
248   31,
249   ' ', '!', '"', '#', '$', '%', '&',
250   '"', // shift-'
251   '(', ')', '*', '+',
252   '<', // shift-,
253   '_', // shift--
254   '>', // shift-.
255   '?', // shift-/
256   ')', // shift-0
257   '!', // shift-1
258   '@', // shift-2
259   '#', // shift-3
260   '$', // shift-4
261   '%', // shift-5
262   '^', // shift-6
263   '&', // shift-7
264   '*', // shift-8
265   '(', // shift-9
266   ':',
267   ':', // shift-;
268   '<',
269   '+', // shift-=
270   '>', '?', '@',
271   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
272   'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
273   '[', // shift-[
274   '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
275   ']', // shift-]
276   '"', '_',
277   '\'', // shift-`
278   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
279   'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
280   '{', '|', '}', '~', 127
281 };
282 
283 //
284 // HU_Init()
285 //
286 // Initialize the heads-up display, text that overwrites the primary display
287 //
288 // Passed nothing, returns nothing
289 //
HU_Init(void)290 void HU_Init(void)
291 {
292 
293   int   i;
294   int   j;
295   char  buffer[9];
296 
297   shiftxform = english_shiftxform;
298 
299   // load the heads-up font
300   j = HU_FONTSTART;
301   for (i=0;i<HU_FONTSIZE;i++,j++)
302   {
303      // IWAD Status font
304      sprintf(buffer, "STCFN%.3d",j);
305      if (W_CheckNumForName(buffer) != -1)
306        R_SetPatchNum(&hu_font[i], buffer);
307 
308      // DIG PrBoom font
309      if ('A'<=j && j<='Z') // letters will use the letter
310        sprintf(buffer, "DIG%c",j);
311      else if ('0'<=j && j<='9') // 0-9 numbers will use the number
312        sprintf(buffer, "DIG%.1d",j-48);
313      else // Otherwise, use the ASCII code
314        sprintf(buffer, "DIG%.1d",j);
315 
316      if (W_CheckNumForName(buffer) != -1)
317        R_SetPatchNum(&hu_font2[i], buffer);
318      else
319        hu_font2[i] = hu_font[i]; // fallback to IWAD font
320   }
321 
322   // CPhipps - load patches for message background
323   for (i=0; i<9; i++) {
324     sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]);
325     if (W_CheckNumForName(buffer) != -1)
326       R_SetPatchNum(&hu_msgbg[i], buffer);
327   }
328 
329   // CPhipps - load patches for keys and double keys
330   for (i=0; i<6; i++) {
331     sprintf(buffer, "STKEYS%d", i);
332     R_SetPatchNum(&hu_fontk[i], buffer);
333   }
334 }
335 
336 //
337 // HU_Stop()
338 //
339 // Make the heads-up displays inactive
340 //
341 // Passed nothing, returns nothing
342 //
HU_Stop(void)343 static void HU_Stop(void)
344 {
345   headsupactive = FALSE;
346 }
347 
348 //
349 // HU_Start(void)
350 //
351 // Create and initialize the heads-up widgets, software machines to
352 // maintain, update, and display information over the primary display
353 //
354 // This routine must be called after any change to the heads up configuration
355 // in order for the changes to take effect in the actual displays
356 //
357 // Passed nothing, returns nothing
358 //
HU_Start(void)359 void HU_Start(void)
360 {
361 
362   int   i;
363   const char* s; /* cph - const */
364   dbool is_distributed = (hud_mode == hud_distributed);
365 
366   if (headsupactive)                    // stop before starting
367     HU_Stop();
368 
369   plr = &players[displayplayer];        // killough 3/7/98
370   message_on = FALSE;
371   message_dontfuckwithme = FALSE;
372   message_nottobefuckedwith = FALSE;
373   chat_on = FALSE;
374 
375   // create the message widget
376   // messages to player in upper-left of screen
377   HUlib_initSText
378   (
379     &w_message,
380     HU_MSGX,
381     HU_MSGY,
382     HU_MSGHEIGHT,
383     hu_font,
384     HU_FONTSTART,
385     hudcolor_mesg,
386     &message_on
387   );
388 
389   //jff 2/16/98 added some HUD widgets
390   // create the map title widget - map title display in lower left of automap
391   HUlib_initTextLine
392   (
393     &w_title,
394     HU_TITLEX,
395     HU_TITLEY,
396     hu_font,
397     HU_FONTSTART,
398     hudcolor_titl
399   );
400 
401   // create the hud health widget
402   // bargraph and number for amount of health,
403   // lower left or upper right of screen
404   HUlib_initTextLine
405   (
406     &w_health,
407     is_distributed? HU_HEALTHX_D : HU_HEALTHX,  //3/4/98 distribute
408     is_distributed? HU_HEALTHY_D : HU_HEALTHY,
409     hu_font2,
410     HU_FONTSTART,
411     CR_GREEN
412   );
413 
414   // create the hud armor widget
415   // bargraph and number for amount of armor,
416   // lower left or upper right of screen
417   HUlib_initTextLine
418   (
419     &w_armor,
420     is_distributed? HU_ARMORX_D : HU_ARMORX,    //3/4/98 distribute
421     is_distributed? HU_ARMORY_D : HU_ARMORY,
422     hu_font2,
423     HU_FONTSTART,
424     CR_GREEN
425   );
426 
427   // create the hud ammo widget
428   // bargraph and number for amount of ammo for current weapon,
429   // lower left or lower right of screen
430   HUlib_initTextLine
431   (
432     &w_ammo,
433     is_distributed? HU_AMMOX_D : HU_AMMOX,      //3/4/98 distribute
434     is_distributed? HU_AMMOY_D : HU_AMMOY,
435     hu_font2,
436     HU_FONTSTART,
437     CR_GOLD
438   );
439 
440   // create the hud weapons widget
441   // list of numbers of weapons possessed
442   // lower left or lower right of screen
443   HUlib_initTextLine
444   (
445     &w_weapon,
446     is_distributed? HU_WEAPX_D : HU_WEAPX,      //3/4/98 distribute
447     is_distributed? HU_WEAPY_D : HU_WEAPY,
448     hu_font2,
449     HU_FONTSTART,
450     CR_GRAY
451   );
452 
453   // create the hud keys widget
454   // display of key letters possessed
455   // lower left of screen
456   HUlib_initTextLine
457   (
458     &w_keys,
459     is_distributed? HU_KEYSX_D : HU_KEYSX,      //3/4/98 distribute
460     is_distributed? HU_KEYSY_D : HU_KEYSY,
461     hu_font2,
462     HU_FONTSTART,
463     CR_GRAY
464   );
465 
466   // create the hud graphic keys widget
467   // display of key graphics possessed
468   // lower left of screen
469   HUlib_initTextLine
470   (
471     &w_gkeys,
472     is_distributed? HU_KEYSGX_D : HU_KEYSGX,    //3/4/98 distribute
473     is_distributed? HU_KEYSY_D : HU_KEYSY,
474     hu_fontk,
475     HU_FONTSTART,
476     CR_RED
477   );
478 
479   // create the hud monster/secret widget
480   // totals and current values for kills, items, secrets
481   // lower left of screen
482   HUlib_initTextLine
483   (
484     &w_monsec,
485     is_distributed? HU_MONSECX_D : HU_MONSECX,  //3/4/98 distribute
486     is_distributed? HU_MONSECY_D : HU_MONSECY,
487     hu_font2,
488     HU_FONTSTART,
489     CR_GRAY
490   );
491 
492   // create the hud text refresh widget
493   // scrolling display of last hud_msg_lines messages received
494   if (hud_msg_lines>HU_MAXMESSAGES)
495     hud_msg_lines=HU_MAXMESSAGES;
496   //jff 4/21/98 if setup has disabled message list while active, turn it off
497   message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways
498   //jff 2/26/98 add the text refresh widget initialization
499   HUlib_initMText
500   (
501     &w_rtext,
502     0,
503     0,
504     320,
505 //    SCREENWIDTH,
506     (hud_msg_lines+2)*HU_REFRESHSPACING,
507     hu_font,
508     HU_FONTSTART,
509     hudcolor_list,
510     hu_msgbg,
511     &message_list
512   );
513 
514   // initialize the automap's level title widget
515   s = NULL;
516   if (gamemapinfo != NULL)
517   {
518     s = gamemapinfo->mapname;
519     while (*s)
520       HUlib_addCharToTextLine(&w_title, *(s++));
521 
522     HUlib_addCharToTextLine(&w_title, ':');
523     HUlib_addCharToTextLine(&w_title, ' ');
524     s = gamemapinfo->levelname;
525   }
526   else
527   {
528     if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */
529     switch (gamemode)
530     {
531       case shareware:
532       case registered:
533       case retail:
534         s = HU_TITLE;
535         break;
536 
537       case commercial:
538       default:  // Ty 08/27/98 - modified to check mission for TNT/Plutonia
539         s = (gamemission==pack_tnt)  ? HU_TITLET :
540             (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2;
541         break;
542     }
543   }
544   if (!s) s = "Unnamed";
545   while (*s)
546     HUlib_addCharToTextLine(&w_title, *(s++));
547 
548   // create the automaps coordinate widget
549   // jff 3/3/98 split coord widget into three lines: x,y,z
550   // jff 2/16/98 added
551   HUlib_initTextLine
552   (
553     &w_coordx,
554     HU_COORDX,
555     HU_COORDX_Y,
556     hu_font,
557     HU_FONTSTART,
558     hudcolor_xyco
559   );
560   HUlib_initTextLine
561   (
562     &w_coordy,
563     HU_COORDX,
564     HU_COORDY_Y,
565     hu_font,
566     HU_FONTSTART,
567     hudcolor_xyco
568   );
569   HUlib_initTextLine
570   (
571     &w_coordz,
572     HU_COORDX,
573     HU_COORDZ_Y,
574     hu_font,
575     HU_FONTSTART,
576     hudcolor_xyco
577   );
578 
579   // initialize the automaps coordinate widget
580   //jff 3/3/98 split coordstr widget into 3 parts
581   if (map_point_coordinates)
582   {
583     sprintf(hud_coordstrx,"X: %-5d",0); //jff 2/22/98 added z
584     s = hud_coordstrx;
585     while (*s)
586       HUlib_addCharToTextLine(&w_coordx, *(s++));
587     sprintf(hud_coordstry,"Y: %-5d",0); //jff 3/3/98 split x,y,z
588     s = hud_coordstry;
589     while (*s)
590       HUlib_addCharToTextLine(&w_coordy, *(s++));
591     sprintf(hud_coordstrz,"Z: %-5d",0); //jff 3/3/98 split x,y,z
592     s = hud_coordstrz;
593     while (*s)
594       HUlib_addCharToTextLine(&w_coordz, *(s++));
595   }
596 
597   //jff 2/16/98 initialize ammo widget
598   strcpy(hud_ammostr,"AMM ");
599   s = hud_ammostr;
600   while (*s)
601     HUlib_addCharToTextLine(&w_ammo, *(s++));
602 
603   //jff 2/16/98 initialize health widget
604   strcpy(hud_healthstr,"HEL ");
605   s = hud_healthstr;
606   while (*s)
607     HUlib_addCharToTextLine(&w_health, *(s++));
608 
609   //jff 2/16/98 initialize armor widget
610   strcpy(hud_armorstr,"ARM ");
611   s = hud_armorstr;
612   while (*s)
613     HUlib_addCharToTextLine(&w_armor, *(s++));
614 
615   //jff 2/17/98 initialize weapons widget
616   strcpy(hud_weapstr,"WEA ");
617   s = hud_weapstr;
618   while (*s)
619     HUlib_addCharToTextLine(&w_weapon, *(s++));
620 
621   //jff 2/17/98 initialize keys widget
622   if (deathmatch) //jff 3/17/98 show frags in deathmatch mode
623     strcpy(hud_keysstr,"FRG ");
624   else
625     hud_keysstr[0] = '\0'; // without keys, empty to save screen space
626   s = hud_keysstr;
627   while (*s)
628     HUlib_addCharToTextLine(&w_keys, *(s++));
629 
630   //jff 2/17/98 initialize graphic keys widget
631   strcpy(hud_gkeysstr," ");
632   s = hud_gkeysstr;
633   while (*s)
634     HUlib_addCharToTextLine(&w_gkeys, *(s++));
635 
636   // initialize kills/items/secret widget as empty string to save screen space
637   hud_monsecstr[0] = '\0';
638   s = hud_monsecstr;
639   while (*s)
640     HUlib_addCharToTextLine(&w_monsec, *(s++));
641 
642   // create the chat widget
643   HUlib_initIText
644   (
645     &w_chat,
646     HU_INPUTX,
647     HU_INPUTY,
648     hu_font,
649     HU_FONTSTART,
650     hudcolor_chat,
651     &chat_on
652   );
653 
654   // create the inputbuffer widgets, one per player
655   for (i=0 ; i<MAXPLAYERS ; i++)
656     HUlib_initIText
657     (
658       &w_inputbuffer[i],
659       0,
660       0,
661       0,
662       0,
663       hudcolor_chat,
664       &always_off
665     );
666 
667   // now allow the heads-up display to run
668   headsupactive = TRUE;
669 }
670 
671 //
672 // HU_MoveHud()
673 //
674 // Move the HUD display from distributed to compact mode or vice-versa
675 //
676 // Passed nothing, returns nothing
677 //
678 //jff 3/9/98 create this externally callable to avoid glitch
679 // when menu scatter's HUD due to delay in change of position
680 //
HU_MoveHud(void)681 void HU_MoveHud(void)
682 {
683   static dbool was_distributed=-1;
684   dbool is_distributed = (hud_mode == hud_distributed);
685 
686   //jff 3/4/98 move displays around on F5 changing hud_distributed
687   if (is_distributed != was_distributed)
688   {
689     w_ammo.x =    is_distributed? HU_AMMOX_D   : HU_AMMOX;
690     w_ammo.y =    is_distributed? HU_AMMOY_D   : HU_AMMOY;
691     w_weapon.x =  is_distributed? HU_WEAPX_D   : HU_WEAPX;
692     w_weapon.y =  is_distributed? HU_WEAPY_D   : HU_WEAPY;
693     w_keys.x =    is_distributed? HU_KEYSX_D   : HU_KEYSX;
694     w_keys.y =    is_distributed? HU_KEYSY_D   : HU_KEYSY;
695     w_gkeys.x =   is_distributed? HU_KEYSGX_D  : HU_KEYSGX;
696     w_gkeys.y =   is_distributed? HU_KEYSY_D   : HU_KEYSY;
697     w_monsec.x =  is_distributed? HU_MONSECX_D : HU_MONSECX;
698     w_monsec.y =  is_distributed? HU_MONSECY_D : HU_MONSECY;
699     w_health.x =  is_distributed? HU_HEALTHX_D : HU_HEALTHX;
700     w_health.y =  is_distributed? HU_HEALTHY_D : HU_HEALTHY;
701     w_armor.x =   is_distributed? HU_ARMORX_D  : HU_ARMORX;
702     w_armor.y =   is_distributed? HU_ARMORY_D  : HU_ARMORY;
703   }
704   was_distributed = is_distributed;
705 }
706 
707 //
708 // HU_Drawer()
709 //
710 // Draw all the pieces of the heads-up display
711 //
712 // Passed nothing, returns nothing
713 //
HU_Drawer(void)714 void HU_Drawer(void)
715 {
716   char *s;
717   player_t *plr;
718   char ammostr[80];  //jff 3/8/98 allow plenty room for dehacked mods
719   char healthstr[80];//jff
720   char armorstr[80]; //jff
721   int doit;
722 
723   // don't draw anything if there's a fullscreen menu up
724   if (menuactive == mnact_full)
725     return;
726 
727   plr = &players[displayplayer];         // killough 3/7/98
728   // draw the automap widgets if automap is displayed
729   if (automapmode & am_active)
730   {
731     // map title
732     HUlib_drawTextLine(&w_title, FALSE);
733 
734     //jff 2/16/98 output new coord display
735     // x-coord
736     if (map_point_coordinates)
737     {
738       sprintf(hud_coordstrx,"X: %-5d", (plr->mo->x)>>FRACBITS);
739       HUlib_clearTextLine(&w_coordx);
740       s = hud_coordstrx;
741       while (*s)
742         HUlib_addCharToTextLine(&w_coordx, *(s++));
743       HUlib_drawTextLine(&w_coordx, FALSE);
744 
745       //jff 3/3/98 split coord display into x,y,z lines
746       // y-coord
747       sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS);
748       HUlib_clearTextLine(&w_coordy);
749       s = hud_coordstry;
750       while (*s)
751         HUlib_addCharToTextLine(&w_coordy, *(s++));
752       HUlib_drawTextLine(&w_coordy, FALSE);
753 
754       //jff 3/3/98 split coord display into x,y,z lines
755       //jff 2/22/98 added z
756       // z-coord
757       sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS);
758       HUlib_clearTextLine(&w_coordz);
759       s = hud_coordstrz;
760       while (*s)
761         HUlib_addCharToTextLine(&w_coordz, *(s++));
762       HUlib_drawTextLine(&w_coordz, FALSE);
763     }
764   }
765 
766   // draw the weapon/health/ammo/armor/kills/keys displays if optioned
767   //jff 2/17/98 allow new hud stuff to be turned off
768   // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY
769   if
770   (
771     hud_mode!=hud_off &&             // hud on from fullscreen key
772     viewheight==SCREENHEIGHT &&      // fullscreen mode is active
773     !(automapmode & am_active)       // automap is not active
774   )
775   {
776     doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems
777     if (doit)            //jff 8/7/98 update every time, avoid lag in update
778     {
779       HU_MoveHud();                  // insure HUD display coords are correct
780 
781       // do the hud ammo display
782       // clear the widgets internal line
783       HUlib_clearTextLine(&w_ammo);
784       strcpy(hud_ammostr,"AMM ");
785       if (weaponinfo[plr->readyweapon].ammo == AM_NOAMMO)
786       { // special case for weapon with no ammo selected - blank bargraph + N/A
787         strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A");
788         w_ammo.cm = CR_GRAY;
789       }
790       else
791       {
792         int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo];
793         int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo];
794         int ammolevel = P_GetAmmoLevel(plr, plr->readyweapon);
795         int ammobars = ammolevel/4;
796         int i;
797 
798         // build the numeric amount init string
799         sprintf(ammostr,"%d/%d",ammo,fullammo);
800         // build the bargraph string
801         // full bargraph chars
802         for (i=4;i<4+ammobars/4;)
803           hud_ammostr[i++] = 123;
804         // plus one last character with 0,1,2,3 bars
805         switch(ammobars%4)
806         {
807           case 0:
808             break;
809           case 1:
810             hud_ammostr[i++] = 126;
811             break;
812           case 2:
813             hud_ammostr[i++] = 125;
814             break;
815           case 3:
816             hud_ammostr[i++] = 124;
817             break;
818         }
819         // pad string with blank bar characters
820         while(i<4+7)
821           hud_ammostr[i++] = 127;
822         hud_ammostr[i] = '\0';
823         strcat(hud_ammostr,ammostr);
824 
825         // set the display color from the percentage of total ammo held
826         if (ammolevel == 0)
827           w_ammo.cm = CR_BROWN;
828         else if (ammolevel >= 100)
829           w_ammo.cm = CR_BLUE;
830         else if (ammolevel < ammo_red)
831           w_ammo.cm = CR_RED;
832         else if (ammolevel < ammo_yellow)
833           w_ammo.cm = CR_GOLD;
834         else
835           w_ammo.cm = CR_GREEN;
836       }
837       // transfer the init string to the widget
838       s = hud_ammostr;
839       while (*s)
840         HUlib_addCharToTextLine(&w_ammo, *(s++));
841     }
842     // display the ammo widget every frame
843     HUlib_drawTextLine(&w_ammo, FALSE);
844 
845     // do the hud health display
846     if (doit)
847     {
848       int health = plr->health;
849       int healthbars = health>100? 25 : health/4;
850       int i;
851 
852       // clear the widgets internal line
853       HUlib_clearTextLine(&w_health);
854 
855       // build the numeric amount init string
856       sprintf(healthstr,"%3d",health);
857       // build the bargraph string
858       // full bargraph chars
859       for (i=4;i<4+healthbars/4;)
860         hud_healthstr[i++] = 123;
861       // plus one last character with 0,1,2,3 bars
862       switch(healthbars%4)
863       {
864         case 0:
865           break;
866         case 1:
867           hud_healthstr[i++] = 126;
868           break;
869         case 2:
870           hud_healthstr[i++] = 125;
871           break;
872         case 3:
873           hud_healthstr[i++] = 124;
874           break;
875       }
876       // pad string with blank bar characters
877       while(i<4+7)
878         hud_healthstr[i++] = 127;
879       hud_healthstr[i] = '\0';
880       strcat(hud_healthstr,healthstr);
881 
882       // set the display color from the amount of health posessed
883       if (health<health_red)
884         w_health.cm = CR_RED;
885       else if (health<health_yellow)
886         w_health.cm = CR_GOLD;
887       else if (health<=health_green)
888         w_health.cm = CR_GREEN;
889       else
890         w_health.cm = CR_BLUE;
891 
892       // transfer the init string to the widget
893       s = hud_healthstr;
894       while (*s)
895         HUlib_addCharToTextLine(&w_health, *(s++));
896     }
897     // display the health widget every frame
898     HUlib_drawTextLine(&w_health, FALSE);
899 
900     // do the hud armor display
901     if (doit)
902     {
903       int armor = plr->armorpoints;
904       int armorbars = armor>100? 25 : armor/4;
905       int i;
906 
907       // clear the widgets internal line
908       HUlib_clearTextLine(&w_armor);
909       // build the numeric amount init string
910       sprintf(armorstr,"%3d",armor);
911       // build the bargraph string
912       // full bargraph chars
913       for (i=4;i<4+armorbars/4;)
914         hud_armorstr[i++] = 123;
915       // plus one last character with 0,1,2,3 bars
916       switch(armorbars%4)
917       {
918         case 0:
919           break;
920         case 1:
921           hud_armorstr[i++] = 126;
922           break;
923         case 2:
924           hud_armorstr[i++] = 125;
925           break;
926         case 3:
927           hud_armorstr[i++] = 124;
928           break;
929       }
930       // pad string with blank bar characters
931       while(i<4+7)
932         hud_armorstr[i++] = 127;
933       hud_armorstr[i] = '\0';
934       strcat(hud_armorstr,armorstr);
935 
936       // set the display color from the amount of armor posessed
937       if (armor<armor_red)
938         w_armor.cm = CR_RED;
939       else if (armor<armor_yellow)
940         w_armor.cm = CR_GOLD;
941       else if (armor<=armor_green)
942         w_armor.cm = CR_GREEN;
943       else
944         w_armor.cm = CR_BLUE;
945 
946       // transfer the init string to the widget
947       s = hud_armorstr;
948       while (*s)
949         HUlib_addCharToTextLine(&w_armor, *(s++));
950     }
951     // display the armor widget every frame
952     HUlib_drawTextLine(&w_armor, FALSE);
953 
954     // do the hud weapon display
955     if(hud_showweapons)
956     {
957       if (doit)
958       {
959         int i, w, ammolevel;
960 
961         // clear the widgets internal line
962         HUlib_clearTextLine(&w_weapon);
963         i=4; hud_weapstr[i] = '\0';      //jff 3/7/98 make sure ammo goes away
964 
965         // do each weapon that exists in current gamemode
966         for (w=0;w <= WP_SUPERSHOTGUN; w++) //jff 3/4/98 show fists too, why not?
967         {
968           int ok=1;
969           //jff avoid executing for weapons that do not exist
970           switch (gamemode)
971           {
972             case shareware:
973               if (w >= WP_PLASMA && w != WP_CHAINSAW)
974                 ok=0;
975               break;
976             case retail:
977             case registered:
978               if (w >= WP_SUPERSHOTGUN)
979                 ok=0;
980               break;
981             default:
982             case commercial:
983               break;
984           }
985           if (!ok) continue;
986 
987           // skip weapons not currently posessed
988           if (!plr->weaponowned[w])
989             continue;
990 
991           ammolevel = P_GetAmmoLevel(plr, w);
992 
993           // display each weapon number in a color related to the ammo for it
994           hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
995           if (weaponinfo[w].ammo == AM_NOAMMO) //jff 3/14/98 show berserk on HUD
996             hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY;
997           else if (ammolevel == 0)
998             hud_weapstr[i++] = '0'+CR_BROWN;
999           else if (ammolevel >= 100)
1000             hud_weapstr[i++] = '0'+CR_BLUE;
1001           else if (ammolevel < ammo_red)
1002             hud_weapstr[i++] = '0'+CR_RED;
1003           else if (ammolevel < ammo_yellow)
1004             hud_weapstr[i++] = '0'+CR_GOLD;
1005           else
1006             hud_weapstr[i++] = '0'+CR_GREEN;
1007           hud_weapstr[i++] = '0'+w+1;
1008           hud_weapstr[i++] = ' ';
1009           hud_weapstr[i] = '\0';
1010         }
1011 
1012         // transfer the init string to the widget
1013         s = hud_weapstr;
1014         while (*s)
1015           HUlib_addCharToTextLine(&w_weapon, *(s++));
1016       }
1017       // display the weapon widget every frame
1018       HUlib_drawTextLine(&w_weapon, FALSE);
1019     }
1020 
1021     // if deathmatch, build string showing top four frag counts
1022     if(deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch
1023     {
1024       int k, top1=-999,top2=-999,top3=-999,top4=-999;
1025       int idx1=-1,idx2=-1,idx3=-1,idx4=-1;
1026       int fragcount,m;
1027       char numbuf[32];
1028       int i = 4; // hud_keysstr index
1029 
1030       // scan thru players
1031       for (k=0;k<MAXPLAYERS;k++)
1032       {
1033         // skip players not in game
1034         if (!playeringame[k])
1035           continue;
1036 
1037         fragcount = 0;
1038         // compute number of times they've fragged each player
1039         // minus number of times they've been fragged by them
1040         for (m=0;m<MAXPLAYERS;m++)
1041         {
1042           if (!playeringame[m]) continue;
1043           fragcount += (m!=k)?  players[k].frags[m] : -players[k].frags[m];
1044         }
1045 
1046         // very primitive sort of frags to find top four
1047         if (fragcount>top1)
1048         {
1049           top4=top3; top3=top2; top2 = top1; top1=fragcount;
1050           idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k;
1051         }
1052         else if (fragcount>top2)
1053         {
1054           top4=top3; top3=top2; top2=fragcount;
1055           idx4=idx3; idx3=idx2; idx2=k;
1056         }
1057         else if (fragcount>top3)
1058         {
1059           top4=top3; top3=fragcount;
1060           idx4=idx3; idx3=k;
1061         }
1062         else if (fragcount>top4)
1063         {
1064           top4=fragcount;
1065           idx4=k;
1066         }
1067       }
1068       // if the biggest number exists, put it in the init string
1069       if (idx1>-1)
1070       {
1071         sprintf(numbuf,"%5d",top1);
1072         // make frag count in player's color via escape code
1073         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1074         hud_keysstr[i++] = '0'+plyrcoltran[idx1&3];
1075         s = numbuf;
1076         while (*s)
1077           hud_keysstr[i++] = *(s++);
1078       }
1079       // if the second biggest number exists, put it in the init string
1080       if (idx2>-1)
1081       {
1082         sprintf(numbuf,"%5d",top2);
1083         // make frag count in player's color via escape code
1084         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1085         hud_keysstr[i++] = '0'+plyrcoltran[idx2&3];
1086         s = numbuf;
1087         while (*s)
1088           hud_keysstr[i++] = *(s++);
1089       }
1090       // if the third biggest number exists, put it in the init string
1091       if (idx3>-1)
1092       {
1093         sprintf(numbuf,"%5d",top3);
1094         // make frag count in player's color via escape code
1095         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1096         hud_keysstr[i++] = '0'+plyrcoltran[idx3&3];
1097         s = numbuf;
1098         while (*s)
1099           hud_keysstr[i++] = *(s++);
1100       }
1101       // if the fourth biggest number exists, put it in the init string
1102       if (idx4>-1)
1103       {
1104         sprintf(numbuf,"%5d",top4);
1105         // make frag count in player's color via escape code
1106         hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1107         hud_keysstr[i++] = '0'+plyrcoltran[idx4&3];
1108         s = numbuf;
1109         while (*s)
1110           hud_keysstr[i++] = *(s++);
1111       }
1112       hud_keysstr[i] = '\0';
1113     } //jff 3/17/98 end of deathmatch clause
1114     else if (hud_showkeys)
1115     {
1116       if (doit)
1117       {
1118         int k;
1119         dbool haskeys = FALSE;
1120 
1121         hud_keysstr[4] = '\0';    //jff 3/7/98 make sure deleted keys go away
1122         //jff add case for graphic key display
1123 
1124         if (hud_graph_keys)
1125         {
1126           int i=0;
1127           hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string
1128           // build text string whose characters call out graphic keys from fontk
1129           for (k=0;k<6;k++)
1130           {
1131             // skip keys not possessed
1132             if (!plr->cards[k])
1133               continue;
1134 
1135             hud_gkeysstr[i++] = '!'+k;   // key number plus '!' is char for key
1136             hud_gkeysstr[i++] = ' ';     // spacing
1137             hud_gkeysstr[i++] = ' ';
1138           }
1139           hud_gkeysstr[i]='\0';
1140           if (i>0) haskeys = TRUE;
1141         }
1142         else
1143         { // This actually is never called, since graphical keys are always set
1144           // build alphabetical key display (not used currently)
1145           int i=4;  // hud_keysstr index
1146           hud_keysstr[i] = '\0';  //jff 3/7/98 make sure deleted keys go away
1147           for (k=0;k<6;k++) // scan the keys
1148           {
1149             // skip any not possessed by the displayed player's stats
1150             if (!plr->cards[k])
1151               continue;
1152 
1153             // use color escapes to make text in key's color
1154             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1155             switch(k)
1156             {
1157               case 0:
1158                 hud_keysstr[i++] = '0'+CR_BLUE;
1159                 hud_keysstr[i++] = 'B';
1160                 hud_keysstr[i++] = 'C';
1161                 hud_keysstr[i++] = ' ';
1162                 break;
1163               case 1:
1164                 hud_keysstr[i++] = '0'+CR_GOLD;
1165                 hud_keysstr[i++] = 'Y';
1166                 hud_keysstr[i++] = 'C';
1167                 hud_keysstr[i++] = ' ';
1168                 break;
1169               case 2:
1170                 hud_keysstr[i++] = '0'+CR_RED;
1171                 hud_keysstr[i++] = 'R';
1172                 hud_keysstr[i++] = 'C';
1173                 hud_keysstr[i++] = ' ';
1174                 break;
1175               case 3:
1176                 hud_keysstr[i++] = '0'+CR_BLUE;
1177                 hud_keysstr[i++] = 'B';
1178                 hud_keysstr[i++] = 'S';
1179                 hud_keysstr[i++] = ' ';
1180                 break;
1181             case 4:
1182                 hud_keysstr[i++] = '0'+CR_GOLD;
1183                 hud_keysstr[i++] = 'Y';
1184                 hud_keysstr[i++] = 'S';
1185                 hud_keysstr[i++] = ' ';
1186                 break;
1187               case 5:
1188                 hud_keysstr[i++] = '0'+CR_RED;
1189                 hud_keysstr[i++] = 'R';
1190                 hud_keysstr[i++] = 'S';
1191                 hud_keysstr[i++] = ' ';
1192                 break;
1193             }
1194             hud_keysstr[i]='\0';
1195             if (i>4) haskeys = TRUE;
1196           }
1197         }
1198         // if we have keys and the line was hidden, show the KEY prefixing text
1199         if (haskeys && hud_keysstr[0] != 'K')
1200           memcpy(hud_keysstr, "KEY ", 4);
1201       }
1202     }
1203     // display the keys/frags line each frame
1204     if (hud_showkeys || deathmatch)
1205     {
1206       HUlib_clearTextLine(&w_keys);      // clear the widget strings
1207       HUlib_clearTextLine(&w_gkeys);
1208 
1209       // transfer the built string (frags or key title) to the widget
1210       s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags
1211       while (*s)
1212         HUlib_addCharToTextLine(&w_keys, *(s++));
1213       HUlib_drawTextLine(&w_keys, FALSE);
1214 
1215       //jff 3/17/98 show graphic keys in non-DM only
1216       if (!deathmatch) //jff 3/7/98 display graphic keys
1217       {
1218         // transfer the graphic key text to the widget
1219         s = hud_gkeysstr;
1220         while (*s)
1221           HUlib_addCharToTextLine(&w_gkeys, *(s++));
1222         // display the widget
1223         HUlib_drawTextLine(&w_gkeys, FALSE);
1224       }
1225     }
1226 
1227     // display the hud kills/items/secret display if optioned
1228     if (hud_showstats)
1229     {
1230       if (doit)
1231       {
1232         // clear the internal widget text buffer
1233         HUlib_clearTextLine(&w_monsec);
1234         //jff 3/26/98 use ESC not '\' for paths
1235         // build the init string with fixed colors
1236         sprintf
1237         (
1238           hud_monsecstr,
1239           "\x1b\x36K\x1b\x33%d\x1b\x36M\x1b\x33%d \x1b\x37I\x1b\x33%d \x1b\x35S\x1b\x33%d/%d",
1240           plr->killcount,totallive,
1241           totalitems-plr->itemcount,
1242           plr->secretcount,totalsecret
1243         );
1244         // transfer the init string to the widget
1245         s = hud_monsecstr;
1246         while (*s)
1247           HUlib_addCharToTextLine(&w_monsec, *(s++));
1248       }
1249       // display the kills/items/secrets each frame
1250       HUlib_drawTextLine(&w_monsec, FALSE);
1251     }
1252   }
1253 
1254   //jff 3/4/98 display last to give priority
1255   HU_Erase(); // jff 4/24/98 Erase current lines before drawing current
1256               // needed when screen not fullsize
1257 
1258   //jff 4/21/98 if setup has disabled message list while active, turn it off
1259   if (hud_msg_lines<=1)
1260     message_list = FALSE;
1261 
1262   // if the message review not enabled, show the standard message widget
1263   if (!message_list)
1264     HUlib_drawSText(&w_message);
1265 
1266   // if the message review is enabled show the scrolling message review
1267   if (hud_msg_lines>1 && message_list)
1268     HUlib_drawMText(&w_rtext);
1269 
1270   // display the interactive buffer for chat entry
1271   HUlib_drawIText(&w_chat);
1272 }
1273 
1274 //
1275 // HU_Erase()
1276 //
1277 // Erase hud display lines that can be trashed by small screen display
1278 //
1279 // Passed nothing, returns nothing
1280 //
HU_Erase(void)1281 void HU_Erase(void)
1282 {
1283   // erase the message display or the message review display
1284   if (!message_list)
1285     HUlib_eraseSText(&w_message);
1286   else
1287     HUlib_eraseMText(&w_rtext);
1288 
1289   // erase the interactive text buffer for chat entry
1290   HUlib_eraseIText(&w_chat);
1291 
1292   // erase the automap title
1293   HUlib_eraseTextLine(&w_title);
1294 }
1295 
1296 //
1297 // HU_Ticker()
1298 //
1299 // Update the hud displays once per frame
1300 //
1301 // Passed nothing, returns nothing
1302 //
1303 static dbool bsdown; // Is backspace down?
1304 static int bscounter;
1305 
HU_Ticker(void)1306 void HU_Ticker(void)
1307 {
1308   int i, rc;
1309   char c;
1310 
1311   // tick down message counter if message is up
1312   if (message_counter && !--message_counter)
1313   {
1314     message_on = FALSE;
1315     message_nottobefuckedwith = FALSE;
1316   }
1317   if (bsdown && bscounter++ > 9) {
1318     HUlib_keyInIText(&w_chat, (unsigned char)key_backspace);
1319     bscounter = 8;
1320   }
1321 
1322   // if messages on, or "Messages Off" is being displayed
1323   // this allows the notification of turning messages off to be seen
1324   if (showMessages || message_dontfuckwithme)
1325   {
1326     // display message if necessary
1327     if ((plr->message && !message_nottobefuckedwith)
1328         || (plr->message && message_dontfuckwithme))
1329     {
1330       //post the message to the message widget
1331       HUlib_addMessageToSText(&w_message, 0, plr->message);
1332       //jff 2/26/98 add message to refresh text widget too
1333       HUlib_addMessageToMText(&w_rtext, 0, plr->message);
1334 
1335       // clear the message to avoid posting multiple times
1336       plr->message = 0;
1337       // note a message is displayed
1338       message_on = TRUE;
1339       // start the message persistence counter
1340       message_counter = HU_MSGTIMEOUT;
1341       // transfer "Messages Off" exception to the "being displayed" variable
1342       message_nottobefuckedwith = message_dontfuckwithme;
1343       // clear the flag that "Messages Off" is being posted
1344       message_dontfuckwithme = 0;
1345     }
1346   }
1347 
1348   // check for incoming chat characters
1349   if (netgame)
1350   {
1351     for (i=0; i<MAXPLAYERS; i++)
1352     {
1353       if (!playeringame[i])
1354         continue;
1355       if (i != consoleplayer
1356           && (c = players[i].cmd.chatchar))
1357       {
1358         if (c <= HU_BROADCAST)
1359           chat_dest[i] = c;
1360         else
1361         {
1362           if (c >= 'a' && c <= 'z')
1363             c = (char) shiftxform[(unsigned char) c];
1364           rc = HUlib_keyInIText(&w_inputbuffer[i], c);
1365           if (rc && c == KEYD_ENTER)
1366           {
1367             if (w_inputbuffer[i].l.len
1368                 && (chat_dest[i] == consoleplayer+1
1369                 || chat_dest[i] == HU_BROADCAST))
1370             {
1371               HUlib_addMessageToSText(&w_message,
1372                                       player_names[i],
1373                                       w_inputbuffer[i].l.l);
1374 
1375               message_nottobefuckedwith = TRUE;
1376               message_on = TRUE;
1377               message_counter = HU_MSGTIMEOUT;
1378               if ( gamemode == commercial )
1379                 S_StartSound(0, sfx_radio);
1380               else
1381                 S_StartSound(0, sfx_tink);
1382             }
1383             HUlib_resetIText(&w_inputbuffer[i]);
1384           }
1385         }
1386         players[i].cmd.chatchar = 0;
1387       }
1388     }
1389   }
1390 }
1391 
1392 #define QUEUESIZE   128
1393 
1394 static char chatchars[QUEUESIZE];
1395 static int  head = 0;
1396 static int  tail = 0;
1397 
1398 //
1399 // HU_queueChatChar()
1400 //
1401 // Add an incoming character to the circular chat queue
1402 //
1403 // Passed the character to queue, returns nothing
1404 //
HU_queueChatChar(char c)1405 static void HU_queueChatChar(char c)
1406 {
1407   if (((head + 1) & (QUEUESIZE-1)) == tail)
1408   {
1409     plr->message = HUSTR_MSGU;
1410   }
1411   else
1412   {
1413     chatchars[head] = c;
1414     head = (head + 1) & (QUEUESIZE-1);
1415   }
1416 }
1417 
1418 //
1419 // HU_dequeueChatChar()
1420 //
1421 // Remove the earliest added character from the circular chat queue
1422 //
1423 // Passed nothing, returns the character dequeued
1424 //
HU_dequeueChatChar(void)1425 char HU_dequeueChatChar(void)
1426 {
1427   char c;
1428 
1429   if (head != tail)
1430   {
1431     c = chatchars[tail];
1432     tail = (tail + 1) & (QUEUESIZE-1);
1433   }
1434   else
1435   {
1436     c = 0;
1437   }
1438   return c;
1439 }
1440 
1441 //
1442 // HU_Responder()
1443 //
1444 // Responds to input events that affect the heads up displays
1445 //
1446 // Passed the event to respond to, returns TRUE if the event was handled
1447 //
HU_Responder(event_t * ev)1448 dbool HU_Responder(event_t *ev)
1449 {
1450 
1451   static char   lastmessage[HU_MAXLINELENGTH+1];
1452   const char*   macromessage; // CPhipps - const char*
1453   dbool   eatkey = FALSE;
1454   static dbool  shiftdown = FALSE;
1455   static dbool  altdown = FALSE;
1456   unsigned char   c;
1457   int     i;
1458   int     numplayers;
1459 
1460   static int    num_nobrainers = 0;
1461 
1462   numplayers = 0;
1463   for (i=0 ; i<MAXPLAYERS ; i++)
1464     numplayers += playeringame[i];
1465 
1466   if (ev->data1 == key_shift)
1467   {
1468     shiftdown = ev->type == ev_keydown;
1469     return FALSE;
1470   }
1471   else if (ev->data1 == key_alt)
1472   {
1473     altdown = ev->type == ev_keydown;
1474     return FALSE;
1475   }
1476   else if (ev->data1 == key_backspace)
1477   {
1478     bsdown = ev->type == ev_keydown;
1479     bscounter = 0;
1480   }
1481 
1482   if (ev->type != ev_keydown)
1483     return FALSE;
1484 
1485   if (!chat_on)
1486   {
1487     if (ev->data1 == key_enter)                                 // phares
1488     {
1489       if (hud_msg_lines>1)  // it posts multi-line messages that will trash
1490       {
1491         if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages
1492         message_list = !message_list; //jff 2/26/98 toggle list of messages
1493       }
1494       if (!message_list)              // if not message list, refresh message
1495       {
1496         message_on = TRUE;
1497         message_counter = HU_MSGTIMEOUT;
1498       }
1499       eatkey = TRUE;
1500     }//jff 2/26/98 no chat if message review is displayed
1501     // killough 10/02/98: no chat if demo playback
1502     // no chat in -solo-net mode
1503     else if (!demoplayback && !message_list && netgame && numplayers > 1)
1504     {
1505       if (ev->data1 == key_chat)
1506     {
1507       eatkey = chat_on = TRUE;
1508       HUlib_resetIText(&w_chat);
1509       HU_queueChatChar(HU_BROADCAST);
1510     }
1511     else if (numplayers > 2)
1512     {
1513       for (i=0; i<MAXPLAYERS ; i++)
1514       {
1515         if (ev->data1 == destination_keys[i])
1516         {
1517           if (playeringame[i] && i!=consoleplayer)
1518           {
1519             eatkey = chat_on = TRUE;
1520             HUlib_resetIText(&w_chat);
1521             HU_queueChatChar((char)(i+1));
1522             break;
1523           }
1524           else if (i == consoleplayer)
1525           {
1526             num_nobrainers++;
1527             if (num_nobrainers < 3)
1528                 plr->message = HUSTR_TALKTOSELF1;
1529             else if (num_nobrainers < 6)
1530                 plr->message = HUSTR_TALKTOSELF2;
1531             else if (num_nobrainers < 9)
1532                 plr->message = HUSTR_TALKTOSELF3;
1533             else if (num_nobrainers < 32)
1534                 plr->message = HUSTR_TALKTOSELF4;
1535             else
1536                 plr->message = HUSTR_TALKTOSELF5;
1537           }
1538         }
1539       }
1540     }
1541     }
1542   }//jff 2/26/98 no chat functions if message review is displayed
1543   else if (!message_list)
1544   {
1545     c = ev->data1;
1546     // send a macro
1547     if (altdown)
1548     {
1549       c = c - '0';
1550       if (c > 9)
1551         return FALSE;
1552       macromessage = chat_macros[c];
1553 
1554       // kill last message with a '\n'
1555         HU_queueChatChar((char)key_enter); // DEBUG!!!                // phares
1556 
1557       // send the macro message
1558       while (*macromessage)
1559         HU_queueChatChar(*macromessage++);
1560       HU_queueChatChar((char)key_enter);                            // phares
1561 
1562       // leave chat mode and notify that it was sent
1563       chat_on = FALSE;
1564       strcpy(lastmessage, chat_macros[c]);
1565       plr->message = lastmessage;
1566       eatkey = TRUE;
1567     }
1568     else
1569     {
1570       if (shiftdown || (c >= 'a' && c <= 'z'))
1571         c = shiftxform[c];
1572       eatkey = HUlib_keyInIText(&w_chat, c);
1573       if (eatkey)
1574         HU_queueChatChar(c);
1575 
1576       if (c == key_enter)                                     // phares
1577       {
1578         chat_on = FALSE;
1579         if (w_chat.l.len)
1580         {
1581           strcpy(lastmessage, w_chat.l.l);
1582           plr->message = lastmessage;
1583         }
1584       }
1585       else if (c == key_escape)                               // phares
1586         chat_on = FALSE;
1587     }
1588   }
1589   return eatkey;
1590 }
1591