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