]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/hu_stuff.c
ac97: fix buffering code, games/doom: enable sound
[plan9front.git] / sys / src / games / doom / hu_stuff.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:  Heads-up displays
20 //
21 //-----------------------------------------------------------------------------
22
23 static const char
24 rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $";
25
26 #include <ctype.h>
27
28 #include "doomdef.h"
29
30 #include "z_zone.h"
31
32 #include "m_swap.h"
33
34 #include "hu_stuff.h"
35 #include "hu_lib.h"
36 #include "w_wad.h"
37
38 #include "s_sound.h"
39
40 #include "doomstat.h"
41
42 // Data.
43 #include "dstrings.h"
44 #include "sounds.h"
45
46 //
47 // Locally used constants, shortcuts.
48 //
49 #define HU_TITLE        (mapnames[(gameepisode-1)*9+gamemap-1])
50 #define HU_TITLE2       (mapnames2[gamemap-1])
51 #define HU_TITLEP       (mapnamesp[gamemap-1])
52 #define HU_TITLET       (mapnamest[gamemap-1])
53 #define HU_TITLEHEIGHT  1
54 #define HU_TITLEX       0
55 #define HU_TITLEY       (167 - SHORT(hu_font[0]->height))
56
57 #define HU_INPUTTOGGLE  't'
58 #define HU_INPUTX       HU_MSGX
59 #define HU_INPUTY       (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1))
60 #define HU_INPUTWIDTH   64
61 #define HU_INPUTHEIGHT  1
62
63
64
65 char*   chat_macros[] =
66 {
67     HUSTR_CHATMACRO0,
68     HUSTR_CHATMACRO1,
69     HUSTR_CHATMACRO2,
70     HUSTR_CHATMACRO3,
71     HUSTR_CHATMACRO4,
72     HUSTR_CHATMACRO5,
73     HUSTR_CHATMACRO6,
74     HUSTR_CHATMACRO7,
75     HUSTR_CHATMACRO8,
76     HUSTR_CHATMACRO9
77 };
78
79 char*   player_names[] =
80 {
81     HUSTR_PLRGREEN,
82     HUSTR_PLRINDIGO,
83     HUSTR_PLRBROWN,
84     HUSTR_PLRRED
85 };
86
87
88 char                    chat_char; // remove later.
89 static player_t*        plr;
90 patch_t*                hu_font[HU_FONTSIZE];
91 static hu_textline_t    w_title;
92 boolean                 chat_on;
93 static hu_itext_t       w_chat;
94 static boolean          always_off = false;
95 static char             chat_dest[MAXPLAYERS];
96 static hu_itext_t w_inputbuffer[MAXPLAYERS];
97
98 static boolean          message_on;
99 boolean                 message_dontfuckwithme;
100 static boolean          message_nottobefuckedwith;
101
102 static hu_stext_t       w_message;
103 static int              message_counter;
104
105 extern int              showMessages;
106 extern boolean          automapactive;
107
108 static boolean          headsupactive = false;
109
110 //
111 // Builtin map names.
112 // The actual names can be found in DStrings.h.
113 //
114
115 char*   mapnames[] =    // DOOM shareware/registered/retail (Ultimate) names.
116 {
117
118     HUSTR_E1M1,
119     HUSTR_E1M2,
120     HUSTR_E1M3,
121     HUSTR_E1M4,
122     HUSTR_E1M5,
123     HUSTR_E1M6,
124     HUSTR_E1M7,
125     HUSTR_E1M8,
126     HUSTR_E1M9,
127
128     HUSTR_E2M1,
129     HUSTR_E2M2,
130     HUSTR_E2M3,
131     HUSTR_E2M4,
132     HUSTR_E2M5,
133     HUSTR_E2M6,
134     HUSTR_E2M7,
135     HUSTR_E2M8,
136     HUSTR_E2M9,
137
138     HUSTR_E3M1,
139     HUSTR_E3M2,
140     HUSTR_E3M3,
141     HUSTR_E3M4,
142     HUSTR_E3M5,
143     HUSTR_E3M6,
144     HUSTR_E3M7,
145     HUSTR_E3M8,
146     HUSTR_E3M9,
147
148     HUSTR_E4M1,
149     HUSTR_E4M2,
150     HUSTR_E4M3,
151     HUSTR_E4M4,
152     HUSTR_E4M5,
153     HUSTR_E4M6,
154     HUSTR_E4M7,
155     HUSTR_E4M8,
156     HUSTR_E4M9,
157
158     "NEWLEVEL",
159     "NEWLEVEL",
160     "NEWLEVEL",
161     "NEWLEVEL",
162     "NEWLEVEL",
163     "NEWLEVEL",
164     "NEWLEVEL",
165     "NEWLEVEL",
166     "NEWLEVEL"
167 };
168
169 char*   mapnames2[] =   // DOOM 2 map names.
170 {
171     HUSTR_1,
172     HUSTR_2,
173     HUSTR_3,
174     HUSTR_4,
175     HUSTR_5,
176     HUSTR_6,
177     HUSTR_7,
178     HUSTR_8,
179     HUSTR_9,
180     HUSTR_10,
181     HUSTR_11,
182         
183     HUSTR_12,
184     HUSTR_13,
185     HUSTR_14,
186     HUSTR_15,
187     HUSTR_16,
188     HUSTR_17,
189     HUSTR_18,
190     HUSTR_19,
191     HUSTR_20,
192         
193     HUSTR_21,
194     HUSTR_22,
195     HUSTR_23,
196     HUSTR_24,
197     HUSTR_25,
198     HUSTR_26,
199     HUSTR_27,
200     HUSTR_28,
201     HUSTR_29,
202     HUSTR_30,
203     HUSTR_31,
204     HUSTR_32
205 };
206
207
208 char*   mapnamesp[] =   // Plutonia WAD map names.
209 {
210     PHUSTR_1,
211     PHUSTR_2,
212     PHUSTR_3,
213     PHUSTR_4,
214     PHUSTR_5,
215     PHUSTR_6,
216     PHUSTR_7,
217     PHUSTR_8,
218     PHUSTR_9,
219     PHUSTR_10,
220     PHUSTR_11,
221         
222     PHUSTR_12,
223     PHUSTR_13,
224     PHUSTR_14,
225     PHUSTR_15,
226     PHUSTR_16,
227     PHUSTR_17,
228     PHUSTR_18,
229     PHUSTR_19,
230     PHUSTR_20,
231         
232     PHUSTR_21,
233     PHUSTR_22,
234     PHUSTR_23,
235     PHUSTR_24,
236     PHUSTR_25,
237     PHUSTR_26,
238     PHUSTR_27,
239     PHUSTR_28,
240     PHUSTR_29,
241     PHUSTR_30,
242     PHUSTR_31,
243     PHUSTR_32
244 };
245
246
247 char *mapnamest[] =     // TNT WAD map names.
248 {
249     THUSTR_1,
250     THUSTR_2,
251     THUSTR_3,
252     THUSTR_4,
253     THUSTR_5,
254     THUSTR_6,
255     THUSTR_7,
256     THUSTR_8,
257     THUSTR_9,
258     THUSTR_10,
259     THUSTR_11,
260         
261     THUSTR_12,
262     THUSTR_13,
263     THUSTR_14,
264     THUSTR_15,
265     THUSTR_16,
266     THUSTR_17,
267     THUSTR_18,
268     THUSTR_19,
269     THUSTR_20,
270         
271     THUSTR_21,
272     THUSTR_22,
273     THUSTR_23,
274     THUSTR_24,
275     THUSTR_25,
276     THUSTR_26,
277     THUSTR_27,
278     THUSTR_28,
279     THUSTR_29,
280     THUSTR_30,
281     THUSTR_31,
282     THUSTR_32
283 };
284
285
286 const char*     shiftxform;
287
288 const char french_shiftxform[] =
289 {
290     0,
291     1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
292     11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
293     21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
294     31,
295     ' ', '!', '"', '#', '$', '%', '&',
296     '"', // shift-'
297     '(', ')', '*', '+',
298     '?', // shift-,
299     '_', // shift--
300     '>', // shift-.
301     '?', // shift-/
302     '0', // shift-0
303     '1', // shift-1
304     '2', // shift-2
305     '3', // shift-3
306     '4', // shift-4
307     '5', // shift-5
308     '6', // shift-6
309     '7', // shift-7
310     '8', // shift-8
311     '9', // shift-9
312     '/',
313     '.', // shift-;
314     '<',
315     '+', // shift-=
316     '>', '?', '@',
317     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
318     'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
319     '[', // shift-[
320     '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
321     ']', // shift-]
322     '"', '_',
323     '\'', // shift-`
324     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
325     'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
326     '{', '|', '}', '~', 127
327
328 };
329
330 const char english_shiftxform[] =
331 {
332
333     0,
334     1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
335     11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
336     21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
337     31,
338     ' ', '!', '"', '#', '$', '%', '&',
339     '"', // shift-'
340     '(', ')', '*', '+',
341     '<', // shift-,
342     '_', // shift--
343     '>', // shift-.
344     '?', // shift-/
345     ')', // shift-0
346     '!', // shift-1
347     '@', // shift-2
348     '#', // shift-3
349     '$', // shift-4
350     '%', // shift-5
351     '^', // shift-6
352     '&', // shift-7
353     '*', // shift-8
354     '(', // shift-9
355     ':',
356     ':', // shift-;
357     '<',
358     '+', // shift-=
359     '>', '?', '@',
360     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
361     'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
362     '[', // shift-[
363     '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
364     ']', // shift-]
365     '"', '_',
366     '\'', // shift-`
367     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
368     'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
369     '{', '|', '}', '~', 127
370 };
371
372 char frenchKeyMap[128]=
373 {
374     0,
375     1,2,3,4,5,6,7,8,9,10,
376     11,12,13,14,15,16,17,18,19,20,
377     21,22,23,24,25,26,27,28,29,30,
378     31,
379     ' ','!','"','#','$','%','&','%','(',')','*','+',';','-',':','!',
380     '0','1','2','3','4','5','6','7','8','9',':','M','<','=','>','?',
381     '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
382     'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^','_',
383     '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
384     'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^',127
385 };
386
387 char ForeignTranslation(unsigned char ch)
388 {
389     return ch < 128 ? frenchKeyMap[ch] : ch;
390 }
391
392 void HU_Init(void)
393 {
394
395     int         i;
396     int         j;
397     char        buffer[9];
398
399     if (french)
400         shiftxform = french_shiftxform;
401     else
402         shiftxform = english_shiftxform;
403
404     // load the heads-up font
405     j = HU_FONTSTART;
406     for (i=0;i<HU_FONTSIZE;i++)
407     {
408         sprintf(buffer, "STCFN%.3d", j++);
409         hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
410     }
411
412 }
413
414 void HU_Stop(void)
415 {
416     headsupactive = false;
417 }
418
419 void HU_Start(void)
420 {
421
422     int         i;
423     char*       s;
424
425     if (headsupactive)
426         HU_Stop();
427
428     plr = &players[consoleplayer];
429     message_on = false;
430     message_dontfuckwithme = false;
431     message_nottobefuckedwith = false;
432     chat_on = false;
433
434     // create the message widget
435     HUlib_initSText(&w_message,
436                     HU_MSGX, HU_MSGY, HU_MSGHEIGHT,
437                     hu_font,
438                     HU_FONTSTART, &message_on);
439
440     // create the map title widget
441     HUlib_initTextLine(&w_title,
442                        HU_TITLEX, HU_TITLEY,
443                        hu_font,
444                        HU_FONTSTART);
445     
446     switch ( gamemode )
447     {
448       case shareware:
449       case registered:
450       case retail:
451         s = HU_TITLE;
452         break;
453
454 /* FIXME
455       case pack_plut:
456         s = HU_TITLEP;
457         break;
458       case pack_tnt:
459         s = HU_TITLET;
460         break;
461 */
462         
463       case commercial:
464       default:
465          s = HU_TITLE2;
466          break;
467     }
468     
469     while (*s)
470         HUlib_addCharToTextLine(&w_title, *(s++));
471
472     // create the chat widget
473     HUlib_initIText(&w_chat,
474                     HU_INPUTX, HU_INPUTY,
475                     hu_font,
476                     HU_FONTSTART, &chat_on);
477
478     // create the inputbuffer widgets
479     for (i=0 ; i<MAXPLAYERS ; i++)
480         HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);
481
482     headsupactive = true;
483
484 }
485
486 void HU_Drawer(void)
487 {
488
489     HUlib_drawSText(&w_message);
490     HUlib_drawIText(&w_chat);
491     if (automapactive)
492         HUlib_drawTextLine(&w_title, false);
493
494 }
495
496 void HU_Erase(void)
497 {
498
499     HUlib_eraseSText(&w_message);
500     HUlib_eraseIText(&w_chat);
501     HUlib_eraseTextLine(&w_title);
502
503 }
504
505 void HU_Ticker(void)
506 {
507
508     int i, rc;
509     char c;
510
511     // tick down message counter if message is up
512     if (message_counter && !--message_counter)
513     {
514         message_on = false;
515         message_nottobefuckedwith = false;
516     }
517
518     if (showMessages || message_dontfuckwithme)
519     {
520
521         // display message if necessary
522         if ((plr->message && !message_nottobefuckedwith)
523             || (plr->message && message_dontfuckwithme))
524         {
525             HUlib_addMessageToSText(&w_message, 0, plr->message);
526             plr->message = 0;
527             message_on = true;
528             message_counter = HU_MSGTIMEOUT;
529             message_nottobefuckedwith = message_dontfuckwithme;
530             message_dontfuckwithme = 0;
531         }
532
533     } // else message_on = false;
534
535     // check for incoming chat characters
536     if (netgame)
537     {
538         for (i=0 ; i<MAXPLAYERS; i++)
539         {
540             if (!playeringame[i])
541                 continue;
542             if (i != consoleplayer
543                 && (c = players[i].cmd.chatchar))
544             {
545                 if (c <= HU_BROADCAST)
546                     chat_dest[i] = c;
547                 else
548                 {
549                     if (c >= 'a' && c <= 'z')
550                         c = (char) shiftxform[(unsigned char) c];
551                     rc = HUlib_keyInIText(&w_inputbuffer[i], c);
552                     if (rc && c == KEY_ENTER)
553                     {
554                         if (w_inputbuffer[i].l.len
555                             && (chat_dest[i] == consoleplayer+1
556                                 || chat_dest[i] == HU_BROADCAST))
557                         {
558                             HUlib_addMessageToSText(&w_message,
559                                                     player_names[i],
560                                                     w_inputbuffer[i].l.l);
561                             
562                             message_nottobefuckedwith = true;
563                             message_on = true;
564                             message_counter = HU_MSGTIMEOUT;
565                             if ( gamemode == commercial )
566                               S_StartSound(0, sfx_radio);
567                             else
568                               S_StartSound(0, sfx_tink);
569                         }
570                         HUlib_resetIText(&w_inputbuffer[i]);
571                     }
572                 }
573                 players[i].cmd.chatchar = 0;
574             }
575         }
576     }
577
578 }
579
580 #define QUEUESIZE               128
581
582 static char     chatchars[QUEUESIZE];
583 static int      head = 0;
584 static int      tail = 0;
585
586
587 void HU_queueChatChar(char c)
588 {
589     if (((head + 1) & (QUEUESIZE-1)) == tail)
590     {
591         plr->message = HUSTR_MSGU;
592     }
593     else
594     {
595         chatchars[head] = c;
596         head = (head + 1) & (QUEUESIZE-1);
597     }
598 }
599
600 char HU_dequeueChatChar(void)
601 {
602     char c;
603
604     if (head != tail)
605     {
606         c = chatchars[tail];
607         tail = (tail + 1) & (QUEUESIZE-1);
608     }
609     else
610     {
611         c = 0;
612     }
613
614     return c;
615 }
616
617 boolean HU_Responder(event_t *ev)
618 {
619
620     static char         lastmessage[HU_MAXLINELENGTH+1];
621     char*               macromessage;
622     boolean             eatkey = false;
623     static boolean      shiftdown = false;
624     static boolean      altdown = false;
625     unsigned char       c;
626     int                 i;
627     int                 numplayers;
628     
629     static char         destination_keys[MAXPLAYERS] =
630     {
631         HUSTR_KEYGREEN,
632         HUSTR_KEYINDIGO,
633         HUSTR_KEYBROWN,
634         HUSTR_KEYRED
635     };
636     
637     static int          num_nobrainers = 0;
638
639     numplayers = 0;
640     for (i=0 ; i<MAXPLAYERS ; i++)
641         numplayers += playeringame[i];
642
643     if (ev->data1 == KEY_RSHIFT)
644     {
645         shiftdown = ev->type == ev_keydown;
646         return false;
647     }
648     else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
649     {
650         altdown = ev->type == ev_keydown;
651         return false;
652     }
653
654     if (ev->type != ev_keydown)
655         return false;
656
657     if (!chat_on)
658     {
659         if (ev->data1 == HU_MSGREFRESH)
660         {
661             message_on = true;
662             message_counter = HU_MSGTIMEOUT;
663             eatkey = true;
664         }
665         else if (netgame && ev->data1 == HU_INPUTTOGGLE)
666         {
667             eatkey = chat_on = true;
668             HUlib_resetIText(&w_chat);
669             HU_queueChatChar(HU_BROADCAST);
670         }
671         else if (netgame && numplayers > 2)
672         {
673             for (i=0; i<MAXPLAYERS ; i++)
674             {
675                 if (ev->data1 == destination_keys[i])
676                 {
677                     if (playeringame[i] && i!=consoleplayer)
678                     {
679                         eatkey = chat_on = true;
680                         HUlib_resetIText(&w_chat);
681                         HU_queueChatChar(i+1);
682                         break;
683                     }
684                     else if (i == consoleplayer)
685                     {
686                         num_nobrainers++;
687                         if (num_nobrainers < 3)
688                             plr->message = HUSTR_TALKTOSELF1;
689                         else if (num_nobrainers < 6)
690                             plr->message = HUSTR_TALKTOSELF2;
691                         else if (num_nobrainers < 9)
692                             plr->message = HUSTR_TALKTOSELF3;
693                         else if (num_nobrainers < 32)
694                             plr->message = HUSTR_TALKTOSELF4;
695                         else
696                             plr->message = HUSTR_TALKTOSELF5;
697                     }
698                 }
699             }
700         }
701     }
702     else
703     {
704         c = ev->data1;
705         // send a macro
706         if (altdown)
707         {
708             c = c - '0';
709             if (c > 9)
710                 return false;
711             // fprintf(stderr, "got here\n");
712             macromessage = chat_macros[c];
713             
714             // kill last message with a '\n'
715             HU_queueChatChar(KEY_ENTER); // DEBUG!!!
716             
717             // send the macro message
718             while (*macromessage)
719                 HU_queueChatChar(*macromessage++);
720             HU_queueChatChar(KEY_ENTER);
721             
722             // leave chat mode and notify that it was sent
723             chat_on = false;
724             strcpy(lastmessage, chat_macros[c]);
725             plr->message = lastmessage;
726             eatkey = true;
727         }
728         else
729         {
730             if (french)
731                 c = ForeignTranslation(c);
732             if (shiftdown || (c >= 'a' && c <= 'z'))
733                 c = shiftxform[c];
734             eatkey = HUlib_keyInIText(&w_chat, c);
735             if (eatkey)
736             {
737                 // static unsigned char buf[20]; // DEBUG
738                 HU_queueChatChar(c);
739                 
740                 // sprintf(buf, "KEY: %d => %d", ev->data1, c);
741                 //      plr->message = buf;
742             }
743             if (c == KEY_ENTER)
744             {
745                 chat_on = false;
746                 if (w_chat.l.len)
747                 {
748                     strcpy(lastmessage, w_chat.l.l);
749                     plr->message = lastmessage;
750                 }
751             }
752             else if (c == KEY_ESCAPE)
753                 chat_on = false;
754         }
755     }
756
757     return eatkey;
758
759 }