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_active;       //jff 2/17/98 controls heads-up display mode
51 int hud_displayed;    //jff 2/23/98 turns heads-up display on/off
52 int hud_nosecrets;    //jff 2/18/98 allows secrets line to be disabled in HUD
53 int hud_distributed;  //jff 3/4/98 display HUD in different places on screen
54 int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics
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-96)
108 #define HU_HUDY_UR 2
109 #define HU_MONSECX_D (HU_HUDX_LL)
110 #define HU_MONSECY_D (HU_HUDY_LL+0*HU_GAPY)
111 #define HU_KEYSX_D   (HU_HUDX_LL)
112 #define HU_KEYSGX_D  (HU_HUDX_LL+4*hu_font2['A'-HU_FONTSTART].width)
113 #define HU_KEYSY_D   (HU_HUDY_LL+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_UR)
119 #define HU_HEALTHY_D (HU_HUDY_UR+0*HU_GAPY)
120 #define HU_ARMORX_D  (HU_HUDX_UR)
121 #define HU_ARMORY_D  (HU_HUDY_UR+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 boolean    always_off = false;
188 static char       chat_dest[MAXPLAYERS];
189 boolean           chat_on;
190 static boolean    message_on;
191 static boolean    message_list; //2/26/98 enable showing list of messages
192 boolean           message_dontfuckwithme;
193 static boolean    message_nottobefuckedwith;
194 static int        message_counter;
195 extern int        showMessages;
196 extern boolean    automapactive;
197 static boolean    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     if ('0'<=j && j<='9')
304     {
305       sprintf(buffer, "DIG%.1d",j-48);
306       R_SetPatchNum(&hu_font2[i], buffer);
307       sprintf(buffer, "STCFN%.3d",j);
308       R_SetPatchNum(&hu_font[i], buffer);
309     }
310     else if ('A'<=j && j<='Z')
311     {
312       sprintf(buffer, "DIG%c",j);
313       R_SetPatchNum(&hu_font2[i], buffer);
314       sprintf(buffer, "STCFN%.3d",j);
315       R_SetPatchNum(&hu_font[i], buffer);
316     }
317     else if (j=='-')
318     {
319       R_SetPatchNum(&hu_font2[i], "DIG45");
320       R_SetPatchNum(&hu_font[i], "STCFN045");
321     }
322     else if (j=='/')
323     {
324       R_SetPatchNum(&hu_font2[i], "DIG47");
325       R_SetPatchNum(&hu_font[i], "STCFN047");
326     }
327     else if (j==':')
328     {
329       R_SetPatchNum(&hu_font2[i], "DIG58");
330       R_SetPatchNum(&hu_font[i], "STCFN058");
331     }
332     else if (j=='[')
333     {
334       R_SetPatchNum(&hu_font2[i], "DIG91");
335       R_SetPatchNum(&hu_font[i], "STCFN091");
336     }
337     else if (j==']')
338     {
339       R_SetPatchNum(&hu_font2[i], "DIG93");
340       R_SetPatchNum(&hu_font[i], "STCFN093");
341     }
342     else if (j<97)
343     {
344       sprintf(buffer, "STCFN%.3d",j);
345       R_SetPatchNum(&hu_font2[i], buffer);
346       R_SetPatchNum(&hu_font[i], buffer);
347       //jff 2/23/98 make all font chars defined, useful or not
348     }
349     else if (j>122)
350     {
351       sprintf(buffer, "STBR%.3d",j);
352       R_SetPatchNum(&hu_font2[i], buffer);
353       R_SetPatchNum(&hu_font[i], buffer);
354     }
355     else
356       hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap
357   }
358 
359   // CPhipps - load patches for message background
360   for (i=0; i<9; i++) {
361     sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]);
362     R_SetPatchNum(&hu_msgbg[i], buffer);
363   }
364 
365   // CPhipps - load patches for keys and double keys
366   for (i=0; i<6; i++) {
367     sprintf(buffer, "STKEYS%d", i);
368     R_SetPatchNum(&hu_fontk[i], buffer);
369   }
370 }
371 
372 //
373 // HU_Stop()
374 //
375 // Make the heads-up displays inactive
376 //
377 // Passed nothing, returns nothing
378 //
HU_Stop(void)379 static void HU_Stop(void)
380 {
381   headsupactive = false;
382 }
383 
384 //
385 // HU_Start(void)
386 //
387 // Create and initialize the heads-up widgets, software machines to
388 // maintain, update, and display information over the primary display
389 //
390 // This routine must be called after any change to the heads up configuration
391 // in order for the changes to take effect in the actual displays
392 //
393 // Passed nothing, returns nothing
394 //
HU_Start(void)395 void HU_Start(void)
396 {
397 
398   int   i;
399   const char* s; /* cph - const */
400 
401   if (headsupactive)                    // stop before starting
402     HU_Stop();
403 
404   plr = &players[displayplayer];        // killough 3/7/98
405   message_on = false;
406   message_dontfuckwithme = false;
407   message_nottobefuckedwith = false;
408   chat_on = false;
409 
410   // create the message widget
411   // messages to player in upper-left of screen
412   HUlib_initSText
413   (
414     &w_message,
415     HU_MSGX,
416     HU_MSGY,
417     HU_MSGHEIGHT,
418     hu_font,
419     HU_FONTSTART,
420     hudcolor_mesg,
421     &message_on
422   );
423 
424   //jff 2/16/98 added some HUD widgets
425   // create the map title widget - map title display in lower left of automap
426   HUlib_initTextLine
427   (
428     &w_title,
429     HU_TITLEX,
430     HU_TITLEY,
431     hu_font,
432     HU_FONTSTART,
433     hudcolor_titl
434   );
435 
436   // create the hud health widget
437   // bargraph and number for amount of health,
438   // lower left or upper right of screen
439   HUlib_initTextLine
440   (
441     &w_health,
442     hud_distributed? HU_HEALTHX_D : HU_HEALTHX,  //3/4/98 distribute
443     hud_distributed? HU_HEALTHY_D : HU_HEALTHY,
444     hu_font2,
445     HU_FONTSTART,
446     CR_GREEN
447   );
448 
449   // create the hud armor widget
450   // bargraph and number for amount of armor,
451   // lower left or upper right of screen
452   HUlib_initTextLine
453   (
454     &w_armor,
455     hud_distributed? HU_ARMORX_D : HU_ARMORX,    //3/4/98 distribute
456     hud_distributed? HU_ARMORY_D : HU_ARMORY,
457     hu_font2,
458     HU_FONTSTART,
459     CR_GREEN
460   );
461 
462   // create the hud ammo widget
463   // bargraph and number for amount of ammo for current weapon,
464   // lower left or lower right of screen
465   HUlib_initTextLine
466   (
467     &w_ammo,
468     hud_distributed? HU_AMMOX_D : HU_AMMOX,      //3/4/98 distribute
469     hud_distributed? HU_AMMOY_D : HU_AMMOY,
470     hu_font2,
471     HU_FONTSTART,
472     CR_GOLD
473   );
474 
475   // create the hud weapons widget
476   // list of numbers of weapons possessed
477   // lower left or lower right of screen
478   HUlib_initTextLine
479   (
480     &w_weapon,
481     hud_distributed? HU_WEAPX_D : HU_WEAPX,      //3/4/98 distribute
482     hud_distributed? HU_WEAPY_D : HU_WEAPY,
483     hu_font2,
484     HU_FONTSTART,
485     CR_GRAY
486   );
487 
488   // create the hud keys widget
489   // display of key letters possessed
490   // lower left of screen
491   HUlib_initTextLine
492   (
493     &w_keys,
494     hud_distributed? HU_KEYSX_D : HU_KEYSX,      //3/4/98 distribute
495     hud_distributed? HU_KEYSY_D : HU_KEYSY,
496     hu_font2,
497     HU_FONTSTART,
498     CR_GRAY
499   );
500 
501   // create the hud graphic keys widget
502   // display of key graphics possessed
503   // lower left of screen
504   HUlib_initTextLine
505   (
506     &w_gkeys,
507     hud_distributed? HU_KEYSGX_D : HU_KEYSGX,    //3/4/98 distribute
508     hud_distributed? HU_KEYSY_D : HU_KEYSY,
509     hu_fontk,
510     HU_FONTSTART,
511     CR_RED
512   );
513 
514   // create the hud monster/secret widget
515   // totals and current values for kills, items, secrets
516   // lower left of screen
517   HUlib_initTextLine
518   (
519     &w_monsec,
520     hud_distributed? HU_MONSECX_D : HU_MONSECX,  //3/4/98 distribute
521     hud_distributed? HU_MONSECY_D : HU_MONSECY,
522     hu_font2,
523     HU_FONTSTART,
524     CR_GRAY
525   );
526 
527   // create the hud text refresh widget
528   // scrolling display of last hud_msg_lines messages received
529   if (hud_msg_lines>HU_MAXMESSAGES)
530     hud_msg_lines=HU_MAXMESSAGES;
531   //jff 4/21/98 if setup has disabled message list while active, turn it off
532   message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways
533   //jff 2/26/98 add the text refresh widget initialization
534   HUlib_initMText
535   (
536     &w_rtext,
537     0,
538     0,
539     320,
540 //    SCREENWIDTH,
541     (hud_msg_lines+2)*HU_REFRESHSPACING,
542     hu_font,
543     HU_FONTSTART,
544     hudcolor_list,
545     hu_msgbg,
546     &message_list
547   );
548 
549   // initialize the automap's level title widget
550   if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */
551   switch (gamemode)
552   {
553     case shareware:
554     case registered:
555     case retail:
556       s = HU_TITLE;
557       break;
558 
559     case commercial:
560     default:  // Ty 08/27/98 - modified to check mission for TNT/Plutonia
561       s = (gamemission==pack_tnt)  ? HU_TITLET :
562           (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2;
563       break;
564   } else s = "";
565   while (*s)
566     HUlib_addCharToTextLine(&w_title, *(s++));
567 
568   // create the automaps coordinate widget
569   // jff 3/3/98 split coord widget into three lines: x,y,z
570   // jff 2/16/98 added
571   HUlib_initTextLine
572   (
573     &w_coordx,
574     HU_COORDX,
575     HU_COORDX_Y,
576     hu_font,
577     HU_FONTSTART,
578     hudcolor_xyco
579   );
580   HUlib_initTextLine
581   (
582     &w_coordy,
583     HU_COORDX,
584     HU_COORDY_Y,
585     hu_font,
586     HU_FONTSTART,
587     hudcolor_xyco
588   );
589   HUlib_initTextLine
590   (
591     &w_coordz,
592     HU_COORDX,
593     HU_COORDZ_Y,
594     hu_font,
595     HU_FONTSTART,
596     hudcolor_xyco
597   );
598 
599   // initialize the automaps coordinate widget
600   //jff 3/3/98 split coordstr widget into 3 parts
601   if (map_point_coordinates)
602   {
603     sprintf(hud_coordstrx,"X: %-5d",0); //jff 2/22/98 added z
604     s = hud_coordstrx;
605     while (*s)
606       HUlib_addCharToTextLine(&w_coordx, *(s++));
607     sprintf(hud_coordstry,"Y: %-5d",0); //jff 3/3/98 split x,y,z
608     s = hud_coordstry;
609     while (*s)
610       HUlib_addCharToTextLine(&w_coordy, *(s++));
611     sprintf(hud_coordstrz,"Z: %-5d",0); //jff 3/3/98 split x,y,z
612     s = hud_coordstrz;
613     while (*s)
614       HUlib_addCharToTextLine(&w_coordz, *(s++));
615   }
616 
617   //jff 2/16/98 initialize ammo widget
618   strcpy(hud_ammostr,"AMM ");
619   s = hud_ammostr;
620   while (*s)
621     HUlib_addCharToTextLine(&w_ammo, *(s++));
622 
623   //jff 2/16/98 initialize health widget
624   strcpy(hud_healthstr,"HEL ");
625   s = hud_healthstr;
626   while (*s)
627     HUlib_addCharToTextLine(&w_health, *(s++));
628 
629   //jff 2/16/98 initialize armor widget
630   strcpy(hud_armorstr,"ARM ");
631   s = hud_armorstr;
632   while (*s)
633     HUlib_addCharToTextLine(&w_armor, *(s++));
634 
635   //jff 2/17/98 initialize weapons widget
636   strcpy(hud_weapstr,"WEA ");
637   s = hud_weapstr;
638   while (*s)
639     HUlib_addCharToTextLine(&w_weapon, *(s++));
640 
641   //jff 2/17/98 initialize keys widget
642   if (!deathmatch) //jff 3/17/98 show frags in deathmatch mode
643     strcpy(hud_keysstr,"KEY ");
644   else
645     strcpy(hud_keysstr,"FRG ");
646   s = hud_keysstr;
647   while (*s)
648     HUlib_addCharToTextLine(&w_keys, *(s++));
649 
650   //jff 2/17/98 initialize graphic keys widget
651   strcpy(hud_gkeysstr," ");
652   s = hud_gkeysstr;
653   while (*s)
654     HUlib_addCharToTextLine(&w_gkeys, *(s++));
655 
656   //jff 2/17/98 initialize kills/items/secret widget
657   strcpy(hud_monsecstr,"STS ");
658   s = hud_monsecstr;
659   while (*s)
660     HUlib_addCharToTextLine(&w_monsec, *(s++));
661 
662   // create the chat widget
663   HUlib_initIText
664   (
665     &w_chat,
666     HU_INPUTX,
667     HU_INPUTY,
668     hu_font,
669     HU_FONTSTART,
670     hudcolor_chat,
671     &chat_on
672   );
673 
674   // create the inputbuffer widgets, one per player
675   for (i=0 ; i<MAXPLAYERS ; i++)
676     HUlib_initIText
677     (
678       &w_inputbuffer[i],
679       0,
680       0,
681       0,
682       0,
683       hudcolor_chat,
684       &always_off
685     );
686 
687   // now allow the heads-up display to run
688   headsupactive = true;
689 }
690 
691 //
692 // HU_MoveHud()
693 //
694 // Move the HUD display from distributed to compact mode or vice-versa
695 //
696 // Passed nothing, returns nothing
697 //
698 //jff 3/9/98 create this externally callable to avoid glitch
699 // when menu scatter's HUD due to delay in change of position
700 //
HU_MoveHud(void)701 void HU_MoveHud(void)
702 {
703   static int ohud_distributed=-1;
704 
705   //jff 3/4/98 move displays around on F5 changing hud_distributed
706   if (hud_distributed!=ohud_distributed)
707   {
708     w_ammo.x =    hud_distributed? HU_AMMOX_D   : HU_AMMOX;
709     w_ammo.y =    hud_distributed? HU_AMMOY_D   : HU_AMMOY;
710     w_weapon.x =  hud_distributed? HU_WEAPX_D   : HU_WEAPX;
711     w_weapon.y =  hud_distributed? HU_WEAPY_D   : HU_WEAPY;
712     w_keys.x =    hud_distributed? HU_KEYSX_D   : HU_KEYSX;
713     w_keys.y =    hud_distributed? HU_KEYSY_D   : HU_KEYSY;
714     w_gkeys.x =   hud_distributed? HU_KEYSGX_D  : HU_KEYSGX;
715     w_gkeys.y =   hud_distributed? HU_KEYSY_D   : HU_KEYSY;
716     w_monsec.x =  hud_distributed? HU_MONSECX_D : HU_MONSECX;
717     w_monsec.y =  hud_distributed? HU_MONSECY_D : HU_MONSECY;
718     w_health.x =  hud_distributed? HU_HEALTHX_D : HU_HEALTHX;
719     w_health.y =  hud_distributed? HU_HEALTHY_D : HU_HEALTHY;
720     w_armor.x =   hud_distributed? HU_ARMORX_D  : HU_ARMORX;
721     w_armor.y =   hud_distributed? HU_ARMORY_D  : HU_ARMORY;
722   }
723   ohud_distributed = hud_distributed;
724 }
725 
726 //
727 // HU_Drawer()
728 //
729 // Draw all the pieces of the heads-up display
730 //
731 // Passed nothing, returns nothing
732 //
HU_Drawer(void)733 void HU_Drawer(void)
734 {
735   char *s;
736   player_t *plr;
737   char ammostr[80];  //jff 3/8/98 allow plenty room for dehacked mods
738   char healthstr[80];//jff
739   char armorstr[80]; //jff
740   int i,doit;
741 
742   plr = &players[displayplayer];         // killough 3/7/98
743   // draw the automap widgets if automap is displayed
744   if (automapmode & am_active)
745   {
746     // map title
747     HUlib_drawTextLine(&w_title, false);
748 
749     //jff 2/16/98 output new coord display
750     // x-coord
751     if (map_point_coordinates)
752     {
753       sprintf(hud_coordstrx,"X: %-5d", (plr->mo->x)>>FRACBITS);
754       HUlib_clearTextLine(&w_coordx);
755       s = hud_coordstrx;
756       while (*s)
757         HUlib_addCharToTextLine(&w_coordx, *(s++));
758       HUlib_drawTextLine(&w_coordx, false);
759 
760       //jff 3/3/98 split coord display into x,y,z lines
761       // y-coord
762       sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS);
763       HUlib_clearTextLine(&w_coordy);
764       s = hud_coordstry;
765       while (*s)
766         HUlib_addCharToTextLine(&w_coordy, *(s++));
767       HUlib_drawTextLine(&w_coordy, false);
768 
769       //jff 3/3/98 split coord display into x,y,z lines
770       //jff 2/22/98 added z
771       // z-coord
772       sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS);
773       HUlib_clearTextLine(&w_coordz);
774       s = hud_coordstrz;
775       while (*s)
776         HUlib_addCharToTextLine(&w_coordz, *(s++));
777       HUlib_drawTextLine(&w_coordz, false);
778     }
779   }
780 
781   // draw the weapon/health/ammo/armor/kills/keys displays if optioned
782   //jff 2/17/98 allow new hud stuff to be turned off
783   // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY
784   if
785   (
786     hud_active>0 &&                  // hud optioned on
787     hud_displayed &&                 // hud on from fullscreen key
788     viewheight==SCREENHEIGHT &&      // fullscreen mode is active
789     !(automapmode & am_active)       // automap is not active
790   )
791   {
792     doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems
793     if (doit)            //jff 8/7/98 update every time, avoid lag in update
794     {
795       HU_MoveHud();                  // insure HUD display coords are correct
796 
797       // do the hud ammo display
798       // clear the widgets internal line
799       HUlib_clearTextLine(&w_ammo);
800       strcpy(hud_ammostr,"AMM ");
801       if (weaponinfo[plr->readyweapon].ammo == am_noammo)
802       { // special case for weapon with no ammo selected - blank bargraph + N/A
803         strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A");
804         w_ammo.cm = CR_GRAY;
805       }
806       else
807       {
808         int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo];
809         int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo];
810         int ammopct = (100*ammo)/fullammo;
811         int ammobars = ammopct/4;
812 
813         // build the numeric amount init string
814         sprintf(ammostr,"%d/%d",ammo,fullammo);
815         // build the bargraph string
816         // full bargraph chars
817         for (i=4;i<4+ammobars/4;)
818           hud_ammostr[i++] = 123;
819         // plus one last character with 0,1,2,3 bars
820         switch(ammobars%4)
821         {
822           case 0:
823             break;
824           case 1:
825             hud_ammostr[i++] = 126;
826             break;
827           case 2:
828             hud_ammostr[i++] = 125;
829             break;
830           case 3:
831             hud_ammostr[i++] = 124;
832             break;
833         }
834         // pad string with blank bar characters
835         while(i<4+7)
836           hud_ammostr[i++] = 127;
837         hud_ammostr[i] = '\0';
838         strcat(hud_ammostr,ammostr);
839 
840         // set the display color from the percentage of total ammo held
841         if (ammopct<ammo_red)
842           w_ammo.cm = CR_RED;
843         else if (ammopct<ammo_yellow)
844           w_ammo.cm = CR_GOLD;
845         else
846           w_ammo.cm = CR_GREEN;
847       }
848       // transfer the init string to the widget
849       s = hud_ammostr;
850       while (*s)
851         HUlib_addCharToTextLine(&w_ammo, *(s++));
852     }
853     // display the ammo widget every frame
854     HUlib_drawTextLine(&w_ammo, false);
855 
856     // do the hud health display
857     if (doit)
858     {
859       int health = plr->health;
860       int healthbars = health>100? 25 : health/4;
861 
862       // clear the widgets internal line
863       HUlib_clearTextLine(&w_health);
864 
865       // build the numeric amount init string
866       sprintf(healthstr,"%3d",health);
867       // build the bargraph string
868       // full bargraph chars
869       for (i=4;i<4+healthbars/4;)
870         hud_healthstr[i++] = 123;
871       // plus one last character with 0,1,2,3 bars
872       switch(healthbars%4)
873       {
874         case 0:
875           break;
876         case 1:
877           hud_healthstr[i++] = 126;
878           break;
879         case 2:
880           hud_healthstr[i++] = 125;
881           break;
882         case 3:
883           hud_healthstr[i++] = 124;
884           break;
885       }
886       // pad string with blank bar characters
887       while(i<4+7)
888         hud_healthstr[i++] = 127;
889       hud_healthstr[i] = '\0';
890       strcat(hud_healthstr,healthstr);
891 
892       // set the display color from the amount of health posessed
893       if (health<health_red)
894         w_health.cm = CR_RED;
895       else if (health<health_yellow)
896         w_health.cm = CR_GOLD;
897       else if (health<=health_green)
898         w_health.cm = CR_GREEN;
899       else
900         w_health.cm = CR_BLUE;
901 
902       // transfer the init string to the widget
903       s = hud_healthstr;
904       while (*s)
905         HUlib_addCharToTextLine(&w_health, *(s++));
906     }
907     // display the health widget every frame
908     HUlib_drawTextLine(&w_health, false);
909 
910     // do the hud armor display
911     if (doit)
912     {
913       int armor = plr->armorpoints;
914       int armorbars = armor>100? 25 : armor/4;
915 
916       // clear the widgets internal line
917       HUlib_clearTextLine(&w_armor);
918       // build the numeric amount init string
919       sprintf(armorstr,"%3d",armor);
920       // build the bargraph string
921       // full bargraph chars
922       for (i=4;i<4+armorbars/4;)
923         hud_armorstr[i++] = 123;
924       // plus one last character with 0,1,2,3 bars
925       switch(armorbars%4)
926       {
927         case 0:
928           break;
929         case 1:
930           hud_armorstr[i++] = 126;
931           break;
932         case 2:
933           hud_armorstr[i++] = 125;
934           break;
935         case 3:
936           hud_armorstr[i++] = 124;
937           break;
938       }
939       // pad string with blank bar characters
940       while(i<4+7)
941         hud_armorstr[i++] = 127;
942       hud_armorstr[i] = '\0';
943       strcat(hud_armorstr,armorstr);
944 
945       // set the display color from the amount of armor posessed
946       if (armor<armor_red)
947         w_armor.cm = CR_RED;
948       else if (armor<armor_yellow)
949         w_armor.cm = CR_GOLD;
950       else if (armor<=armor_green)
951         w_armor.cm = CR_GREEN;
952       else
953         w_armor.cm = CR_BLUE;
954 
955       // transfer the init string to the widget
956       s = hud_armorstr;
957       while (*s)
958         HUlib_addCharToTextLine(&w_armor, *(s++));
959     }
960     // display the armor widget every frame
961     HUlib_drawTextLine(&w_armor, false);
962 
963     // do the hud weapon display
964     if (doit)
965     {
966       int w;
967       int ammo,fullammo,ammopct;
968 
969       // clear the widgets internal line
970       HUlib_clearTextLine(&w_weapon);
971       i=4; hud_weapstr[i] = '\0';      //jff 3/7/98 make sure ammo goes away
972 
973       // do each weapon that exists in current gamemode
974       for (w=0;w<=wp_supershotgun;w++) //jff 3/4/98 show fists too, why not?
975       {
976         int ok=1;
977         //jff avoid executing for weapons that do not exist
978         switch (gamemode)
979         {
980           case shareware:
981             if (w>=wp_plasma && w!=wp_chainsaw)
982               ok=0;
983             break;
984           case retail:
985           case registered:
986             if (w>=wp_supershotgun)
987               ok=0;
988             break;
989           default:
990           case commercial:
991             break;
992         }
993         if (!ok) continue;
994 
995         ammo = plr->ammo[weaponinfo[w].ammo];
996         fullammo = plr->maxammo[weaponinfo[w].ammo];
997         ammopct=0;
998 
999         // skip weapons not currently posessed
1000         if (!plr->weaponowned[w])
1001           continue;
1002 
1003         ammopct = fullammo? (100*ammo)/fullammo : 100;
1004 
1005         // display each weapon number in a color related to the ammo for it
1006         hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1007         if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD
1008           hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY;
1009         else if (ammopct<ammo_red)
1010           hud_weapstr[i++] = '0'+CR_RED;
1011         else if (ammopct<ammo_yellow)
1012           hud_weapstr[i++] = '0'+CR_GOLD;
1013         else
1014           hud_weapstr[i++] = '0'+CR_GREEN;
1015         hud_weapstr[i++] = '0'+w+1;
1016         hud_weapstr[i++] = ' ';
1017         hud_weapstr[i] = '\0';
1018       }
1019 
1020       // transfer the init string to the widget
1021       s = hud_weapstr;
1022       while (*s)
1023         HUlib_addCharToTextLine(&w_weapon, *(s++));
1024     }
1025     // display the weapon widget every frame
1026     HUlib_drawTextLine(&w_weapon, false);
1027 
1028     if (doit && hud_active>1)
1029     {
1030       int k;
1031 
1032       hud_keysstr[4] = '\0';    //jff 3/7/98 make sure deleted keys go away
1033       //jff add case for graphic key display
1034       if (!deathmatch && hud_graph_keys)
1035       {
1036         i=0;
1037         hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string
1038         // build text string whose characters call out graphic keys from fontk
1039         for (k=0;k<6;k++)
1040         {
1041           // skip keys not possessed
1042           if (!plr->cards[k])
1043             continue;
1044 
1045           hud_gkeysstr[i++] = '!'+k;   // key number plus '!' is char for key
1046           hud_gkeysstr[i++] = ' ';     // spacing
1047           hud_gkeysstr[i++] = ' ';
1048         }
1049         hud_gkeysstr[i]='\0';
1050       }
1051       else // not possible in current code, unless deathmatching,
1052       {
1053         i=4;
1054         hud_keysstr[i] = '\0';  //jff 3/7/98 make sure deleted keys go away
1055 
1056         // if deathmatch, build string showing top four frag counts
1057         if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch
1058         {
1059           int top1=-999,top2=-999,top3=-999,top4=-999;
1060           int idx1=-1,idx2=-1,idx3=-1,idx4=-1;
1061           int fragcount,m;
1062           char numbuf[32];
1063 
1064           // scan thru players
1065           for (k=0;k<MAXPLAYERS;k++)
1066           {
1067             // skip players not in game
1068             if (!playeringame[k])
1069               continue;
1070 
1071             fragcount = 0;
1072             // compute number of times they've fragged each player
1073             // minus number of times they've been fragged by them
1074             for (m=0;m<MAXPLAYERS;m++)
1075             {
1076               if (!playeringame[m]) continue;
1077               fragcount += (m!=k)?  players[k].frags[m] : -players[k].frags[m];
1078             }
1079 
1080             // very primitive sort of frags to find top four
1081             if (fragcount>top1)
1082             {
1083               top4=top3; top3=top2; top2 = top1; top1=fragcount;
1084               idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k;
1085             }
1086             else if (fragcount>top2)
1087             {
1088               top4=top3; top3=top2; top2=fragcount;
1089               idx4=idx3; idx3=idx2; idx2=k;
1090             }
1091             else if (fragcount>top3)
1092             {
1093               top4=top3; top3=fragcount;
1094               idx4=idx3; idx3=k;
1095             }
1096             else if (fragcount>top4)
1097             {
1098               top4=fragcount;
1099               idx4=k;
1100             }
1101           }
1102           // if the biggest number exists, put it in the init string
1103           if (idx1>-1)
1104           {
1105             sprintf(numbuf,"%5d",top1);
1106             // make frag count in player's color via escape code
1107             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1108             hud_keysstr[i++] = '0'+plyrcoltran[idx1&3];
1109             s = numbuf;
1110             while (*s)
1111               hud_keysstr[i++] = *(s++);
1112           }
1113           // if the second biggest number exists, put it in the init string
1114           if (idx2>-1)
1115           {
1116             sprintf(numbuf,"%5d",top2);
1117             // make frag count in player's color via escape code
1118             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1119             hud_keysstr[i++] = '0'+plyrcoltran[idx2&3];
1120             s = numbuf;
1121             while (*s)
1122               hud_keysstr[i++] = *(s++);
1123           }
1124           // if the third biggest number exists, put it in the init string
1125           if (idx3>-1)
1126           {
1127             sprintf(numbuf,"%5d",top3);
1128             // make frag count in player's color via escape code
1129             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1130             hud_keysstr[i++] = '0'+plyrcoltran[idx3&3];
1131             s = numbuf;
1132             while (*s)
1133               hud_keysstr[i++] = *(s++);
1134           }
1135           // if the fourth biggest number exists, put it in the init string
1136           if (idx4>-1)
1137           {
1138             sprintf(numbuf,"%5d",top4);
1139             // make frag count in player's color via escape code
1140             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1141             hud_keysstr[i++] = '0'+plyrcoltran[idx4&3];
1142             s = numbuf;
1143             while (*s)
1144               hud_keysstr[i++] = *(s++);
1145           }
1146           hud_keysstr[i] = '\0';
1147         } //jff 3/17/98 end of deathmatch clause
1148         else // build alphabetical key display (not used currently)
1149         {
1150           // scan the keys
1151           for (k=0;k<6;k++)
1152           {
1153             // skip any not possessed by the displayed player's stats
1154             if (!plr->cards[k])
1155               continue;
1156 
1157             // use color escapes to make text in key's color
1158             hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths
1159             switch(k)
1160             {
1161               case 0:
1162                 hud_keysstr[i++] = '0'+CR_BLUE;
1163                 hud_keysstr[i++] = 'B';
1164                 hud_keysstr[i++] = 'C';
1165                 hud_keysstr[i++] = ' ';
1166                 break;
1167               case 1:
1168                 hud_keysstr[i++] = '0'+CR_GOLD;
1169                 hud_keysstr[i++] = 'Y';
1170                 hud_keysstr[i++] = 'C';
1171                 hud_keysstr[i++] = ' ';
1172                 break;
1173               case 2:
1174                 hud_keysstr[i++] = '0'+CR_RED;
1175                 hud_keysstr[i++] = 'R';
1176                 hud_keysstr[i++] = 'C';
1177                 hud_keysstr[i++] = ' ';
1178                 break;
1179               case 3:
1180                 hud_keysstr[i++] = '0'+CR_BLUE;
1181                 hud_keysstr[i++] = 'B';
1182                 hud_keysstr[i++] = 'S';
1183                 hud_keysstr[i++] = ' ';
1184                 break;
1185             case 4:
1186                 hud_keysstr[i++] = '0'+CR_GOLD;
1187                 hud_keysstr[i++] = 'Y';
1188                 hud_keysstr[i++] = 'S';
1189                 hud_keysstr[i++] = ' ';
1190                 break;
1191               case 5:
1192                 hud_keysstr[i++] = '0'+CR_RED;
1193                 hud_keysstr[i++] = 'R';
1194                 hud_keysstr[i++] = 'S';
1195                 hud_keysstr[i++] = ' ';
1196                 break;
1197             }
1198             hud_keysstr[i]='\0';
1199           }
1200         }
1201       }
1202     }
1203     // display the keys/frags line each frame
1204     if (hud_active>1)
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_nosecrets)
1229     {
1230       if (hud_active>1 && 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           "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d",
1240           plr->killcount,totallive,
1241           plr->itemcount,totalitems,
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, if optioned
1250       if (hud_active>1)
1251         HUlib_drawTextLine(&w_monsec, false);
1252     }
1253   }
1254 
1255   //jff 3/4/98 display last to give priority
1256   HU_Erase(); // jff 4/24/98 Erase current lines before drawing current
1257               // needed when screen not fullsize
1258 
1259   //jff 4/21/98 if setup has disabled message list while active, turn it off
1260   if (hud_msg_lines<=1)
1261     message_list = false;
1262 
1263   // if the message review not enabled, show the standard message widget
1264   if (!message_list)
1265     HUlib_drawSText(&w_message);
1266 
1267   // if the message review is enabled show the scrolling message review
1268   if (hud_msg_lines>1 && message_list)
1269     HUlib_drawMText(&w_rtext);
1270 
1271   // display the interactive buffer for chat entry
1272   HUlib_drawIText(&w_chat);
1273 }
1274 
1275 //
1276 // HU_Erase()
1277 //
1278 // Erase hud display lines that can be trashed by small screen display
1279 //
1280 // Passed nothing, returns nothing
1281 //
HU_Erase(void)1282 void HU_Erase(void)
1283 {
1284   // erase the message display or the message review display
1285   if (!message_list)
1286     HUlib_eraseSText(&w_message);
1287   else
1288     HUlib_eraseMText(&w_rtext);
1289 
1290   // erase the interactive text buffer for chat entry
1291   HUlib_eraseIText(&w_chat);
1292 
1293   // erase the automap title
1294   HUlib_eraseTextLine(&w_title);
1295 }
1296 
1297 //
1298 // HU_Ticker()
1299 //
1300 // Update the hud displays once per frame
1301 //
1302 // Passed nothing, returns nothing
1303 //
1304 static boolean bsdown; // Is backspace down?
1305 static int bscounter;
1306 
HU_Ticker(void)1307 void HU_Ticker(void)
1308 {
1309   int i, rc;
1310   char c;
1311 
1312   // tick down message counter if message is up
1313   if (message_counter && !--message_counter)
1314   {
1315     message_on = false;
1316     message_nottobefuckedwith = false;
1317   }
1318   if (bsdown && bscounter++ > 9) {
1319     HUlib_keyInIText(&w_chat, (unsigned char)key_backspace);
1320     bscounter = 8;
1321   }
1322 
1323   // if messages on, or "Messages Off" is being displayed
1324   // this allows the notification of turning messages off to be seen
1325   if (showMessages || message_dontfuckwithme)
1326   {
1327     // display message if necessary
1328     if ((plr->message && !message_nottobefuckedwith)
1329         || (plr->message && message_dontfuckwithme))
1330     {
1331       //post the message to the message widget
1332       HUlib_addMessageToSText(&w_message, 0, plr->message);
1333       //jff 2/26/98 add message to refresh text widget too
1334       HUlib_addMessageToMText(&w_rtext, 0, plr->message);
1335 
1336       // clear the message to avoid posting multiple times
1337       plr->message = 0;
1338       // note a message is displayed
1339       message_on = true;
1340       // start the message persistence counter
1341       message_counter = HU_MSGTIMEOUT;
1342       // transfer "Messages Off" exception to the "being displayed" variable
1343       message_nottobefuckedwith = message_dontfuckwithme;
1344       // clear the flag that "Messages Off" is being posted
1345       message_dontfuckwithme = 0;
1346     }
1347   }
1348 
1349   // check for incoming chat characters
1350   if (netgame)
1351   {
1352     for (i=0; i<MAXPLAYERS; i++)
1353     {
1354       if (!playeringame[i])
1355         continue;
1356       if (i != consoleplayer
1357           && (c = players[i].cmd.chatchar))
1358       {
1359         if (c <= HU_BROADCAST)
1360           chat_dest[i] = c;
1361         else
1362         {
1363           if (c >= 'a' && c <= 'z')
1364             c = (char) shiftxform[(unsigned char) c];
1365           rc = HUlib_keyInIText(&w_inputbuffer[i], c);
1366           if (rc && c == KEYD_ENTER)
1367           {
1368             if (w_inputbuffer[i].l.len
1369                 && (chat_dest[i] == consoleplayer+1
1370                 || chat_dest[i] == HU_BROADCAST))
1371             {
1372               HUlib_addMessageToSText(&w_message,
1373                                       player_names[i],
1374                                       w_inputbuffer[i].l.l);
1375 
1376               message_nottobefuckedwith = true;
1377               message_on = true;
1378               message_counter = HU_MSGTIMEOUT;
1379               if ( gamemode == commercial )
1380                 S_StartSound(0, sfx_radio);
1381               else
1382                 S_StartSound(0, sfx_tink);
1383             }
1384             HUlib_resetIText(&w_inputbuffer[i]);
1385           }
1386         }
1387         players[i].cmd.chatchar = 0;
1388       }
1389     }
1390   }
1391 }
1392 
1393 #define QUEUESIZE   128
1394 
1395 static char chatchars[QUEUESIZE];
1396 static int  head = 0;
1397 static int  tail = 0;
1398 
1399 //
1400 // HU_queueChatChar()
1401 //
1402 // Add an incoming character to the circular chat queue
1403 //
1404 // Passed the character to queue, returns nothing
1405 //
HU_queueChatChar(char c)1406 static void HU_queueChatChar(char c)
1407 {
1408   if (((head + 1) & (QUEUESIZE-1)) == tail)
1409   {
1410     plr->message = HUSTR_MSGU;
1411   }
1412   else
1413   {
1414     chatchars[head] = c;
1415     head = (head + 1) & (QUEUESIZE-1);
1416   }
1417 }
1418 
1419 //
1420 // HU_dequeueChatChar()
1421 //
1422 // Remove the earliest added character from the circular chat queue
1423 //
1424 // Passed nothing, returns the character dequeued
1425 //
HU_dequeueChatChar(void)1426 char HU_dequeueChatChar(void)
1427 {
1428   char c;
1429 
1430   if (head != tail)
1431   {
1432     c = chatchars[tail];
1433     tail = (tail + 1) & (QUEUESIZE-1);
1434   }
1435   else
1436   {
1437     c = 0;
1438   }
1439   return c;
1440 }
1441 
1442 //
1443 // HU_Responder()
1444 //
1445 // Responds to input events that affect the heads up displays
1446 //
1447 // Passed the event to respond to, returns true if the event was handled
1448 //
HU_Responder(event_t * ev)1449 boolean HU_Responder(event_t *ev)
1450 {
1451 
1452   static char   lastmessage[HU_MAXLINELENGTH+1];
1453   const char*   macromessage; // CPhipps - const char*
1454   boolean   eatkey = false;
1455   static boolean  shiftdown = false;
1456   static boolean  altdown = false;
1457   unsigned char   c;
1458   int     i;
1459   int     numplayers;
1460 
1461   static int    num_nobrainers = 0;
1462 
1463   numplayers = 0;
1464   for (i=0 ; i<MAXPLAYERS ; i++)
1465     numplayers += playeringame[i];
1466 
1467   if (ev->data1 == key_shift)
1468   {
1469     shiftdown = ev->type == ev_keydown;
1470     return false;
1471   }
1472   else if (ev->data1 == key_alt)
1473   {
1474     altdown = ev->type == ev_keydown;
1475     return false;
1476   }
1477   else if (ev->data1 == key_backspace)
1478   {
1479     bsdown = ev->type == ev_keydown;
1480     bscounter = 0;
1481   }
1482 
1483   if (ev->type != ev_keydown)
1484     return false;
1485 
1486   if (!chat_on)
1487   {
1488     if (ev->data1 == key_enter)                                 // phares
1489     {
1490 #ifndef INSTRUMENTED  // never turn on message review if INSTRUMENTED defined
1491       if (hud_msg_lines>1)  // it posts multi-line messages that will trash
1492       {
1493         if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages
1494         message_list = !message_list; //jff 2/26/98 toggle list of messages
1495       }
1496 #endif
1497       if (!message_list)              // if not message list, refresh message
1498       {
1499         message_on = true;
1500         message_counter = HU_MSGTIMEOUT;
1501       }
1502       eatkey = true;
1503     }//jff 2/26/98 no chat if message review is displayed
1504     // killough 10/02/98: no chat if demo playback
1505     // no chat in -solo-net mode
1506     else if (!demoplayback && !message_list && netgame && numplayers > 1)
1507     {
1508       if (ev->data1 == key_chat)
1509     {
1510       eatkey = chat_on = true;
1511       HUlib_resetIText(&w_chat);
1512       HU_queueChatChar(HU_BROADCAST);
1513     }
1514     else if (numplayers > 2)
1515     {
1516       for (i=0; i<MAXPLAYERS ; i++)
1517       {
1518         if (ev->data1 == destination_keys[i])
1519         {
1520           if (playeringame[i] && i!=consoleplayer)
1521           {
1522             eatkey = chat_on = true;
1523             HUlib_resetIText(&w_chat);
1524             HU_queueChatChar((char)(i+1));
1525             break;
1526           }
1527           else if (i == consoleplayer)
1528           {
1529             num_nobrainers++;
1530             if (num_nobrainers < 3)
1531                 plr->message = HUSTR_TALKTOSELF1;
1532             else if (num_nobrainers < 6)
1533                 plr->message = HUSTR_TALKTOSELF2;
1534             else if (num_nobrainers < 9)
1535                 plr->message = HUSTR_TALKTOSELF3;
1536             else if (num_nobrainers < 32)
1537                 plr->message = HUSTR_TALKTOSELF4;
1538             else
1539                 plr->message = HUSTR_TALKTOSELF5;
1540           }
1541         }
1542       }
1543     }
1544     }
1545   }//jff 2/26/98 no chat functions if message review is displayed
1546   else if (!message_list)
1547   {
1548     c = ev->data1;
1549     // send a macro
1550     if (altdown)
1551     {
1552       c = c - '0';
1553       if (c > 9)
1554         return false;
1555       macromessage = chat_macros[c];
1556 
1557       // kill last message with a '\n'
1558         HU_queueChatChar((char)key_enter); // DEBUG!!!                // phares
1559 
1560       // send the macro message
1561       while (*macromessage)
1562         HU_queueChatChar(*macromessage++);
1563       HU_queueChatChar((char)key_enter);                            // phares
1564 
1565       // leave chat mode and notify that it was sent
1566       chat_on = false;
1567       strcpy(lastmessage, chat_macros[c]);
1568       plr->message = lastmessage;
1569       eatkey = true;
1570     }
1571     else
1572     {
1573       if (shiftdown || (c >= 'a' && c <= 'z'))
1574         c = shiftxform[c];
1575       eatkey = HUlib_keyInIText(&w_chat, c);
1576       if (eatkey)
1577         HU_queueChatChar(c);
1578 
1579       if (c == key_enter)                                     // phares
1580       {
1581         chat_on = false;
1582         if (w_chat.l.len)
1583         {
1584           strcpy(lastmessage, w_chat.l.l);
1585           plr->message = lastmessage;
1586         }
1587       }
1588       else if (c == key_escape)                               // phares
1589         chat_on = false;
1590     }
1591   }
1592   return eatkey;
1593 }
1594