]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/mn_menu.c
osezer patch 010
[theoddone33/hhexen.git] / base / mn_menu.c
1 //**************************************************************************
2 //**
3 //** mn_menu.c : Heretic 2 : Raven Software, Corp.
4 //**
5 //** $RCSfile$
6 //** $Revision$
7 //** $Date$
8 //** $Author$
9 //**
10 //**************************************************************************
11
12 // HEADER FILES ------------------------------------------------------------
13
14 #include <ctype.h>
15 #include "h2def.h"
16 #include "p_local.h"
17 #include "r_local.h"
18 #include "soundst.h"
19
20 #ifdef RENDER3D
21 #include "ogl_def.h"
22 #endif
23
24 // MACROS ------------------------------------------------------------------
25
26 #define LEFT_DIR 0
27 #define RIGHT_DIR 1
28 #define ITEM_HEIGHT 20
29 #define SMALL_ITEM_HEIGHT 9
30 #define MENU_MAX_MOUSE_SENS 50
31
32 #define KEY_INS         (0x80+0x52)
33 #define KEY_DEL         (0x80+0x53)
34 #define KEY_PGUP        (0x80+0x49)
35 #define KEY_PGDN        (0x80+0x51)
36 #define KEY_HOME        (0x80+0x47)
37 #define KEY_END         (0x80+0x4f)
38 #define SELECTOR_XOFFSET (-28)
39 #define SELECTOR_YOFFSET (-1)
40 #define SLOTTEXTLEN     16
41 #define ASCII_CURSOR '['
42
43 // TYPES -------------------------------------------------------------------
44
45 typedef enum
46 {
47         ITT_EMPTY,
48         ITT_EFUNC,
49         ITT_LRFUNC,
50         ITT_SETMENU,
51         ITT_INERT,
52         ITT_SETKEY
53 } ItemType_t;
54
55 typedef enum
56 {
57         MENU_MAIN,
58         MENU_CLASS,
59         MENU_SKILL,
60         MENU_OPTIONS,
61         MENU_OPTIONS2,
62         MENU_OPTIONS3,
63         MENU_FILES,
64         MENU_LOAD,
65         MENU_SAVE,
66         MENU_NONE
67 } MenuType_t;
68
69 typedef struct
70 {
71         ItemType_t type;
72         char *text;
73         void (*func)(int option);
74         int option;
75         MenuType_t menu;
76 } MenuItem_t;
77
78 typedef struct
79 {
80         int x;
81         int y;
82         void (*drawFunc)(void);
83         int itemCount;
84         MenuItem_t *items;
85         int oldItPos;
86         int step;
87         MenuType_t prevMenu;
88
89 #ifdef RENDER3D
90 #if 0
91     void (*textDrawer)(char*,int,int);
92     int itemHeight;
93 #endif
94 #endif
95
96 } Menu_t;
97
98 char *mlooktext[] =
99 {
100         "OFF",
101         "NORMAL",
102         "INVERSE"
103 };
104
105 boolean cdaudio;
106
107 extern int alwaysrun;
108 extern boolean i_CDMusic;
109 extern int I_CDMusInit( void );
110 extern int I_CDMusStop( void );
111
112 extern int mouselook;
113
114 extern int key_right,key_left,key_up,key_down;
115 extern int key_straferight,key_strafeleft,key_jump;
116 extern int key_fire, key_use, key_strafe, key_speed;
117 extern int key_flyup, key_flydown, key_flycenter;
118 extern int key_lookup, key_lookdown, key_lookcenter;
119 extern int key_invleft, key_invright, key_useartifact;
120
121 char *stupidtable[] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N",
122 "O","P","Q","R","S","T","U","V","W","X","Y","Z"};
123
124 extern default_t defaults[];
125 int FirstKey = 0;
126
127 boolean askforkey = false;
128 int keyaskedfor;
129 int *mbone, *mbtwo, *mbthree;
130
131 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
132
133 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
134
135 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
136
137 char *Key2String(int key);
138 void ClearControls(int key);
139 static void InitFonts(void);
140 static void SetMenu(MenuType_t menu);
141 static void SCQuitGame(int option);
142 static void SCClass(int option);
143 static void SCSkill(int option);
144 static void SCMouseSensi(int option);
145 static void SCSfxVolume(int option);
146 static void SCMusicVolume(int option);
147 static void SCScreenSize(int option);
148 static boolean SCNetCheck(int option);
149 static void SCNetCheck2(int option);
150 static void SCLoadGame(int option);
151 static void SCSaveGame(int option);
152 static void SCMessages(int option);
153 static void SCEndGame(int option);
154 static void SCInfo(int option);
155 static void SCSetKey(int option);
156 static void SCMouselook(int option);
157 static void SCAlwaysRun(int option);
158 static void SCCDAudio(int option);
159 static void DrawMainMenu(void);
160 static void DrawClassMenu(void);
161 static void DrawSkillMenu(void);
162 static void DrawOptionsMenu(void);
163 static void DrawOptions2Menu(void);
164 static void DrawOptions3Menu(void);
165 static void DrawFileSlots(Menu_t *menu);
166 static void DrawFilesMenu(void);
167 static void MN_DrawInfo(void);
168 static void DrawLoadMenu(void);
169 static void DrawSaveMenu(void);
170 static void DrawSlider(Menu_t *menu, int item, int width, int slot);
171 void MN_LoadSlotText(void);
172
173 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
174
175 extern int detailLevel;
176 extern int screenblocks;
177 extern char *basePath;
178 extern int key_speed, key_strafe;
179 extern boolean gamekeydown[256]; // The NUMKEYS macro is local to g_game
180
181 // PUBLIC DATA DEFINITIONS -------------------------------------------------
182
183 boolean MenuActive;
184 int InfoType;
185 boolean messageson;
186 boolean mn_SuicideConsole;
187
188 // PRIVATE DATA DEFINITIONS ------------------------------------------------
189
190 static int FontABaseLump;
191 static int FontAYellowBaseLump;
192 static int FontBBaseLump;
193 static int MauloBaseLump;
194 static Menu_t *CurrentMenu;
195 static int CurrentItPos;
196 static int MenuPClass;
197 static int MenuTime;
198 static boolean soundchanged;
199
200 #ifdef RENDER3D
201 static float bgAlpha = 0;
202 static float outFade = 0;
203 static boolean fadingOut = false;
204 static int menuDarkTicks = 15;
205 static int slamInTicks = 9;
206 #endif
207
208 boolean askforquit;
209 boolean typeofask;
210 static boolean FileMenuKeySteal;
211 static boolean slottextloaded;
212 static char SlotText[6][SLOTTEXTLEN+2];
213 static char oldSlotText[SLOTTEXTLEN+2];
214 static int SlotStatus[6];
215 static int slotptr;
216 static int currentSlot;
217 static int quicksave;
218 static int quickload;
219
220 static MenuItem_t MainItems[] =
221 {
222         { ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS },
223         { ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS },
224         { ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES },
225         { ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE },
226         { ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE }
227 };
228
229 static Menu_t MainMenu =
230 {
231         110, 56,
232         DrawMainMenu,
233         5, MainItems,
234         0,
235         ITEM_HEIGHT,
236         MENU_NONE
237 };
238
239 static MenuItem_t ClassItems[] =
240 {
241         { ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE },
242         { ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE },
243         { ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE }
244 #ifdef ASSASSIN 
245         ,{ ITT_EFUNC, "ASSASSIN", SCClass, 3, MENU_NONE }
246 #endif
247 };
248
249 static Menu_t ClassMenu =
250 {
251         66, 66,
252         DrawClassMenu,
253 #ifdef ASSASSIN 
254         4
255 #else 
256         3
257 #endif
258         , ClassItems,
259         0,
260         ITEM_HEIGHT,
261         MENU_MAIN
262 };
263
264 static MenuItem_t FilesItems[] =
265 {
266         { ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD },
267         { ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE }
268 };
269
270 static Menu_t FilesMenu =
271 {
272         110, 60,
273         DrawFilesMenu,
274         2, FilesItems,
275         0,
276         ITEM_HEIGHT,
277         MENU_MAIN
278 };
279
280 static MenuItem_t LoadItems[] =
281 {
282         { ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE },
283         { ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE },
284         { ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE },
285         { ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE },
286         { ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE },
287         { ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE }
288 };
289
290 static Menu_t LoadMenu =
291 {
292         70, 30,
293         DrawLoadMenu,
294         6, LoadItems,
295         0,
296         ITEM_HEIGHT,
297         MENU_FILES
298 };
299
300 static MenuItem_t SaveItems[] =
301 {
302         { ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE },
303         { ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE },
304         { ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE },
305         { ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE },
306         { ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE },
307         { ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE }
308 };
309
310 static Menu_t SaveMenu =
311 {
312         70, 30,
313         DrawSaveMenu,
314         6, SaveItems,
315         0,
316         ITEM_HEIGHT,
317         MENU_FILES
318 };
319
320 static MenuItem_t SkillItems[] =
321 {
322         { ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE },
323         { ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE },
324         { ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE },
325         { ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE },
326         { ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE }
327 };
328
329 static Menu_t SkillMenu =
330 {
331         120, 44,
332         DrawSkillMenu,
333         5, SkillItems,
334         2,
335         ITEM_HEIGHT,
336         MENU_CLASS
337 };
338
339 static MenuItem_t OptionsItems[] =
340 {
341         { ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE },
342         { ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE },
343         { ITT_LRFUNC, "MOUSE SENSITIVITY :", SCMouseSensi, 0, MENU_NONE },
344         { ITT_SETMENU, "CONTROL SETUP", NULL, 0, MENU_OPTIONS3 },
345         { ITT_LRFUNC, "MOUSELOOK : ", SCMouselook, 0, MENU_NONE },
346         { ITT_EFUNC, "ALWAYS RUN : ", SCAlwaysRun, 0, MENU_NONE },
347         { ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2 }
348 };
349
350 static Menu_t OptionsMenu =
351 {
352         88, 30,
353         DrawOptionsMenu,
354         7,
355         OptionsItems,
356         0,
357         ITEM_HEIGHT,
358         MENU_MAIN
359 };
360
361 static MenuItem_t Options2Items[] =
362 {
363         { ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE },
364         { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
365         { ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE },
366         { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
367         { ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE },
368         { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
369         { ITT_EFUNC, "CD AUDIO :", SCCDAudio, 0, MENU_NONE }
370 };
371
372 static Menu_t Options2Menu =
373 {
374         90, 20,
375         DrawOptions2Menu,
376         7,
377         Options2Items,
378         0,
379         ITEM_HEIGHT,
380         MENU_OPTIONS
381 };
382
383 static MenuItem_t Options3Items[] =
384 {
385 /* see defaults[] in m_misc.c for the correct option number:
386  * key_right corresponds to defaults[3], which means that we
387  * are using the (index_number - 3) here.
388  */
389         { ITT_SETKEY, "TURN RIGHT :", SCSetKey, 0, MENU_NONE },
390         { ITT_SETKEY, "TURN LEFT :", SCSetKey, 1, MENU_NONE },
391         { ITT_SETKEY, "MOVE FORWARD :", SCSetKey, 2, MENU_NONE },
392         { ITT_SETKEY, "MOVE BACK :" , SCSetKey, 3, MENU_NONE },
393         { ITT_SETKEY, "STRAFE LEFT :", SCSetKey, 4, MENU_NONE },
394         { ITT_SETKEY, "STRAFE RIGHT :", SCSetKey, 5, MENU_NONE },
395         { ITT_SETKEY, "JUMP :", SCSetKey, 6, MENU_NONE },
396         { ITT_SETKEY, "FLY UP :", SCSetKey, 7, MENU_NONE },
397         { ITT_SETKEY, "FLY DOWN :", SCSetKey, 8, MENU_NONE },
398         { ITT_SETKEY, "FLY CENTER :", SCSetKey, 9, MENU_NONE },
399         { ITT_SETKEY, "LOOK UP :", SCSetKey, 10, MENU_NONE },
400         { ITT_SETKEY, "LOOK DOWN :", SCSetKey, 11, MENU_NONE },
401         { ITT_SETKEY, "LOOK CENTER :", SCSetKey, 12, MENU_NONE },
402         { ITT_SETKEY, "INVETORY LEFT :", SCSetKey, 13, MENU_NONE },
403         { ITT_SETKEY, "INVENTORY RIGHT :", SCSetKey, 14, MENU_NONE },
404         { ITT_SETKEY, "USE ARTIFACT :", SCSetKey, 15, MENU_NONE },
405         { ITT_SETKEY, "FIRE :", SCSetKey, 16, MENU_NONE },
406         { ITT_SETKEY, "USE :", SCSetKey, 17, MENU_NONE },
407         { ITT_SETKEY, "STRAFE :", SCSetKey, 18, MENU_NONE },
408         { ITT_SETKEY, "SPEED :", SCSetKey, 19, MENU_NONE }
409 };
410 static Menu_t Options3Menu = 
411 {
412         70,20,
413         DrawOptions3Menu,
414         15, Options3Items,
415         0,
416         SMALL_ITEM_HEIGHT,
417         MENU_OPTIONS
418 };
419
420 static Menu_t *Menus[] =
421 {
422         &MainMenu,
423         &ClassMenu,
424         &SkillMenu,
425         &OptionsMenu,
426         &Options2Menu,
427         &Options3Menu,
428         &FilesMenu,
429         &LoadMenu,
430         &SaveMenu
431 };
432
433 #if defined(__linux) || #defined(__FreeBSD__)
434 static char *GammaText[] = 
435 {
436         TXT_GAMMA_LEVEL_OFF,
437         TXT_GAMMA_LEVEL_1,
438         TXT_GAMMA_LEVEL_2,
439         TXT_GAMMA_LEVEL_3,
440         TXT_GAMMA_LEVEL_4
441 };
442 #endif
443         
444 // CODE --------------------------------------------------------------------
445 char *Key2String(int key)
446 {
447   switch(key) {
448         case KEY_RIGHTARROW:
449         return "RIGHT ARROW";
450         case KEY_LEFTARROW:
451         return "LEFT ARROW";
452         case KEY_DOWNARROW:
453         return "DOWN ARROW";
454         case KEY_UPARROW:
455         return "UP ARROW";
456         case KEY_ENTER:
457         return "ENTER";
458         case KEY_PGUP:
459         return "PAGE UP";
460         case KEY_PGDN:
461         return "PAGE DOWN";
462         case KEY_INS:
463         return "INSERT";
464         case KEY_HOME:
465         return "HOME";
466         case KEY_END:
467         return "END";
468         case KEY_DEL:
469         return "DELETE";
470         case ' ':
471         return "SPACE";
472         case KEY_RSHIFT:
473         return "SHIFT";
474         case KEY_RALT:
475         return "ALT";
476         case KEY_RCTRL:
477         return "CTRL";
478   }
479   //Handle letter keys
480   if(key >= 'a' && key <= 'z') return stupidtable[(key - 'a')];
481   //Everything else
482   return " ";
483 }
484
485 void ClearControls(int key)
486 {
487         int i;
488
489         for(i=3;i<24;i++)
490         {
491                 if(*defaults[i].location == key) *defaults[i].location = 0;
492         }
493 }
494
495 //---------------------------------------------------------------------------
496 //
497 // PROC MN_Init
498 //
499 //---------------------------------------------------------------------------
500
501 void MN_Init(void)
502 {
503         InitFonts();
504         MenuActive = false;
505 //      messageson = true;              // Set by defaults in .CFG
506         MauloBaseLump = W_GetNumForName("FBULA0"); // ("M_SKL00");
507 }
508
509 //---------------------------------------------------------------------------
510 //
511 // PROC InitFonts
512 //
513 //---------------------------------------------------------------------------
514
515 static void InitFonts(void)
516 {
517         FontABaseLump = W_GetNumForName("FONTA_S")+1;
518         FontAYellowBaseLump = W_GetNumForName("FONTAY_S")+1;
519         FontBBaseLump = W_GetNumForName("FONTB_S")+1;
520 }
521
522 //---------------------------------------------------------------------------
523 //
524 // PROC MN_DrTextA
525 //
526 // Draw text using font A.
527 //
528 //---------------------------------------------------------------------------
529
530 void MN_DrTextA(char *text, int x, int y)
531 {
532         char c;
533         patch_t *p;
534
535 #ifdef RENDER3D
536     OGL_SetColorAndAlpha( 1, 1, 1, 1 );
537 #endif
538
539         while((c = *text++) != 0)
540         {
541                 if(c < 33)
542                 {
543                         x += 5;
544                 }
545                 else
546                 {
547                         p = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
548 #ifdef RENDER3D
549             OGL_DrawPatch_CS(x, y, FontABaseLump+c-33);
550 #else
551                         V_DrawPatch(x, y, p);
552 #endif
553                         x += p->width-1;
554                 }
555         }
556 }
557
558 //==========================================================================
559 //
560 // MN_DrTextAYellow
561 //
562 //==========================================================================
563
564 void MN_DrTextAYellow(char *text, int x, int y)
565 {
566         char c;
567         patch_t *p;
568
569 #ifdef RENDER3D
570     OGL_SetColorAndAlpha( 1, 1, 1, 1 );
571 #endif
572
573         while((c = *text++) != 0)
574         {
575                 if(c < 33)
576                 {
577                         x += 5;
578                 }
579                 else
580                 {
581                         p = W_CacheLumpNum(FontAYellowBaseLump+c-33, PU_CACHE);
582 #ifdef RENDER3D
583             OGL_DrawPatch_CS(x, y, FontAYellowBaseLump+c-33);
584 #else
585                         V_DrawPatch(x, y, p);
586 #endif
587                         x += p->width-1;
588                 }
589         }
590 }
591
592 //---------------------------------------------------------------------------
593 //
594 // FUNC MN_TextAWidth
595 //
596 // Returns the pixel width of a string using font A.
597 //
598 //---------------------------------------------------------------------------
599
600 int MN_TextAWidth(char *text)
601 {
602         char c;
603         int width;
604         patch_t *p;
605
606         width = 0;
607         while((c = *text++) != 0)
608         {
609                 if(c < 33)
610                 {
611                         width += 5;
612                 }
613                 else
614                 {
615                         p = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
616                         width += p->width-1;
617                 }
618         }
619         return(width);
620 }
621
622 //---------------------------------------------------------------------------
623 //
624 // PROC MN_DrTextB
625 //
626 // Draw text using font B.
627 //
628 //---------------------------------------------------------------------------
629
630 void MN_DrTextB(char *text, int x, int y)
631 {
632         char c;
633         patch_t *p;
634
635 #ifdef RENDER3D
636     OGL_SetColorAndAlpha( 1, 1, 1, 1 );
637 #endif
638
639         while((c = *text++) != 0)
640         {
641                 if(c < 33)
642                 {
643                         x += 8;
644                 }
645                 else
646                 {
647                         p = W_CacheLumpNum(FontBBaseLump+c-33, PU_CACHE);
648 #ifdef RENDER3D
649             OGL_DrawPatch_CS(x, y, FontBBaseLump+c-33);
650 #else
651                         V_DrawPatch(x, y, p);
652 #endif
653                         x += p->width-1;
654                 }
655         }
656 }
657
658 //---------------------------------------------------------------------------
659 //
660 // FUNC MN_TextBWidth
661 //
662 // Returns the pixel width of a string using font B.
663 //
664 //---------------------------------------------------------------------------
665
666 int MN_TextBWidth(char *text)
667 {
668         char c;
669         int width;
670         patch_t *p;
671
672         width = 0;
673         while((c = *text++) != 0)
674         {
675                 if(c < 33)
676                 {
677                         width += 5;
678                 }
679                 else
680                 {
681                         p = W_CacheLumpNum(FontBBaseLump+c-33, PU_CACHE);
682                         width += p->width-1;
683                 }
684         }
685         return(width);
686 }
687
688 //---------------------------------------------------------------------------
689 //
690 // PROC MN_Ticker
691 //
692 //---------------------------------------------------------------------------
693
694 void MN_Ticker(void)
695 {
696         if(MenuActive == false)
697         {
698 #ifdef RENDER3D
699         if(bgAlpha > 0)
700         {
701             bgAlpha -= .5/(float)menuDarkTicks;
702             if(bgAlpha < 0) bgAlpha = 0;
703         }
704         if(fadingOut)
705         {
706             outFade += 1/(float)slamInTicks;
707             if(outFade > 1) fadingOut = false;
708         }
709 #endif
710                 return;
711         }
712         MenuTime++;
713 }
714
715
716 #ifdef RENDER3D
717 void MN_OGL_SetupState(float time)
718 {
719     glMatrixMode(GL_MODELVIEW);
720     glPushMatrix();
721  
722     if(time > 1 && time <= 2)
723     {
724         time = 2-time;
725         glTranslatef(160, 100, 0);
726         glScalef(.9+time*.1, .9+time*.1, 1);
727         glTranslatef(-160, -100, 0);
728         glColor4f(1, 1, 1, time);
729         return;
730     }
731  
732     glTranslatef(160, 100, 0);
733     glScalef(2-time, 2-time, 1);
734     glTranslatef(-160, -100, 0);
735     glColor4f(1, 1, 1, time*time);
736 }
737  
738 void MN_OGL_RestoreState()
739 {
740     glMatrixMode(GL_MODELVIEW);
741     glPopMatrix();                                                              
742 }
743 #endif
744
745
746 //---------------------------------------------------------------------------
747 //
748 // PROC MN_Drawer
749 //
750 //---------------------------------------------------------------------------
751
752 char *QuitEndMsg[] =
753 {
754         "ARE YOU SURE YOU WANT TO QUIT?",
755         "ARE YOU SURE YOU WANT TO END THE GAME?",
756         "DO YOU WANT TO QUICKSAVE THE GAME NAMED",
757         "DO YOU WANT TO QUICKLOAD THE GAME NAMED",
758         "ARE YOU SURE YOU WANT TO SUICIDE?"
759 };
760
761
762 #define BETA_FLASH_TEXT "BETA"
763
764 void MN_Drawer(void)
765 {
766         int i;
767         int x;
768         int y;
769         MenuItem_t *item;
770         char *selName;
771
772
773         if(MenuActive == false)
774         {
775 #ifdef RENDER3D
776         if(bgAlpha > 0)
777         {
778             UpdateState |= I_FULLSCRN;
779             BorderNeedRefresh = true;
780             //OGL_SetNoTexture();
781             glDisable( GL_TEXTURE_2D );
782             OGL_DrawRect(0,0,320,200,0,0,0,bgAlpha);
783             glEnable( GL_TEXTURE_2D );
784         }
785 #endif
786                 if(askforquit)
787                 {
788                         MN_DrTextA(QuitEndMsg[typeofask-1], 160-
789                                 MN_TextAWidth(QuitEndMsg[typeofask-1])/2, 80);
790                         if(typeofask == 3)
791                         {
792                                 MN_DrTextA(SlotText[quicksave-1], 160-
793                                         MN_TextAWidth(SlotText[quicksave-1])/2, 90);
794                                 MN_DrTextA("?", 160+
795                                         MN_TextAWidth(SlotText[quicksave-1])/2, 90);
796                         }
797                         if(typeofask == 4)
798                         {
799                                 MN_DrTextA(SlotText[quickload-1], 160-
800                                         MN_TextAWidth(SlotText[quickload-1])/2, 90);
801                                 MN_DrTextA("?", 160+
802                                         MN_TextAWidth(SlotText[quicksave-1])/2, 90);
803                         }
804                         UpdateState |= I_FULLSCRN;
805                 }
806         }
807 #ifdef RENDER3D
808     if( MenuActive || fadingOut )
809     {
810         int effTime = (MenuTime>menuDarkTicks)? menuDarkTicks : MenuTime;
811         float temp = .5 * effTime/(float)menuDarkTicks;
812  
813         UpdateState |= I_FULLSCRN;
814  
815         if(!fadingOut)
816         {
817             if(temp > bgAlpha) bgAlpha = temp;
818             effTime = (MenuTime>slamInTicks)? slamInTicks : MenuTime;
819             temp = effTime / (float)slamInTicks;
820  
821             // Draw a dark background. It makes it easier to read the menus.
822             //OGL_SetNoTexture();
823             glDisable( GL_TEXTURE_2D );
824             OGL_DrawRect(0,0,320,200,0,0,0,bgAlpha);
825             glEnable( GL_TEXTURE_2D );
826         }
827         else temp = outFade+1;
828         MN_OGL_SetupState(temp);
829  
830         if(InfoType)
831         {
832             MN_DrawInfo();
833             MN_OGL_RestoreState();
834             return;
835         }
836         //if(screenblocks < 10)
837         //{
838         BorderNeedRefresh = true;
839         //}
840         if(CurrentMenu->drawFunc != NULL)
841         {
842             CurrentMenu->drawFunc();
843         }
844         x = CurrentMenu->x;
845         y = CurrentMenu->y;
846         item = CurrentMenu->items;
847         if(item->type == ITT_SETKEY)
848                 item += FirstKey;
849         for(i = 0; i < CurrentMenu->itemCount; i++)
850         {
851                         switch(item->type)
852                         {
853                                 case (ITT_EMPTY):
854                                         break;
855                                 case (ITT_SETKEY):
856                                         if(item->text) 
857                                                 MN_DrTextA(item->text, x, y+6);
858                                         break;
859                                 default:
860                                         if(item->text)
861                                                 MN_DrTextB(item->text, x, y);
862                         }
863                         y += CurrentMenu->step;
864             item++;
865         }
866                 y = CurrentMenu->y+(CurrentItPos*CurrentMenu->step)+SELECTOR_YOFFSET;
867         selName = MenuTime&16 ? "M_SLCTR1" : "M_SLCTR2";
868         OGL_DrawPatch_CS(x+SELECTOR_XOFFSET, y, W_GetNumForName(selName));
869  
870         MN_OGL_RestoreState();
871     }
872 #else
873         else
874         {
875                 UpdateState |= I_FULLSCRN;
876                 if(InfoType)
877                 {
878                         MN_DrawInfo();
879                         return;
880                 }
881                 if(screenblocks < 10)
882                 {
883                         BorderNeedRefresh = true;
884                 }
885                 if(CurrentMenu->drawFunc != NULL)
886                 {
887                         CurrentMenu->drawFunc();
888                 }
889                 x = CurrentMenu->x;
890                 y = CurrentMenu->y;
891                 item = CurrentMenu->items;
892                 if(item->type == ITT_SETKEY)
893                         item += FirstKey;
894                 for(i = 0; i < CurrentMenu->itemCount; i++)
895                 {
896                         switch(item->type)
897                         {
898                                 case (ITT_EMPTY):
899                                         break;
900                                 case (ITT_SETKEY):
901                                         if(item->text) 
902                                                 MN_DrTextA(item->text, x, y+6);
903                                         break;
904                                 default:
905                                         if(item->text)
906                                                 MN_DrTextB(item->text, x, y);
907                         }
908                         y += CurrentMenu->step;
909                         item++;
910                 }
911                 y = CurrentMenu->y+(CurrentItPos*CurrentMenu->step)+SELECTOR_YOFFSET;
912                 selName = MenuTime&16 ? "M_SLCTR1" : "M_SLCTR2";
913                 V_DrawPatch(x+SELECTOR_XOFFSET, y,
914                         W_CacheLumpName(selName, PU_CACHE));
915         }
916 #endif
917 }
918
919 //---------------------------------------------------------------------------
920 //
921 // PROC DrawMainMenu
922 //
923 //---------------------------------------------------------------------------
924
925 static void DrawMainMenu(void)
926 {
927         int frame;
928
929         frame = (MenuTime/5)%7;
930
931 #ifdef RENDER3D
932     OGL_DrawPatch_CS( 88, 0, W_GetNumForName("M_HTIC") );
933     OGL_DrawPatch_CS( 37, 80, MauloBaseLump+(frame+2)%7 );
934     OGL_DrawPatch_CS( 278, 80, MauloBaseLump+frame );
935 #else
936         V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE));
937 // Old Gold skull positions: (40, 10) and (232, 10)
938         V_DrawPatch(37, 80, W_CacheLumpNum(MauloBaseLump+(frame+2)%7, 
939                 PU_CACHE));
940         V_DrawPatch(278, 80, W_CacheLumpNum(MauloBaseLump+frame, PU_CACHE));
941 #endif
942 }
943
944 //==========================================================================
945 //
946 // DrawClassMenu
947 //
948 //==========================================================================
949
950 static void DrawClassMenu(void)
951 {
952         pclass_t class;
953         static char *boxLumpName[4] =
954         {
955                 "m_fbox",
956                 "m_cbox",
957                 "m_mbox",
958                 "m_abox"
959         };
960         static char *walkLumpName[4] =
961         {
962                 "m_fwalk1",
963                 "m_cwalk1",
964                 "m_mwalk1",
965                 "m_awalk1"
966         };
967
968         MN_DrTextB("CHOOSE CLASS:", 34, 24);
969         class = (pclass_t)CurrentMenu->items[CurrentItPos].option;
970 #ifdef RENDER3D
971     OGL_DrawPatch_CS(174, 8, W_GetNumForName(boxLumpName[class]));
972     OGL_DrawPatch_CS(174+24, 8+12,
973             W_GetNumForName(walkLumpName[class])+((MenuTime>>3)&3));
974 #else
975         V_DrawPatch(174, 8, W_CacheLumpName(boxLumpName[class], PU_CACHE));
976         V_DrawPatch(174+24, 8+12,
977                 W_CacheLumpNum(W_GetNumForName(walkLumpName[class])
978                 +((MenuTime>>3)&3), PU_CACHE));
979 #endif
980 }
981
982 //---------------------------------------------------------------------------
983 //
984 // PROC DrawSkillMenu
985 //
986 //---------------------------------------------------------------------------
987
988 static void DrawSkillMenu(void)
989 {
990         MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16);
991 }
992
993 //---------------------------------------------------------------------------
994 //
995 // PROC DrawFilesMenu
996 //
997 //---------------------------------------------------------------------------
998
999 static void DrawFilesMenu(void)
1000 {
1001 // clear out the quicksave/quickload stuff
1002         quicksave = 0;
1003         quickload = 0;
1004         P_ClearMessage(&players[consoleplayer]);
1005 }
1006
1007 //---------------------------------------------------------------------------
1008 //
1009 // PROC DrawLoadMenu
1010 //
1011 //---------------------------------------------------------------------------
1012
1013 static void DrawLoadMenu(void)
1014 {
1015         MN_DrTextB("LOAD GAME", 160-MN_TextBWidth("LOAD GAME")/2, 10);
1016         if(!slottextloaded)
1017         {
1018                 MN_LoadSlotText();
1019         }
1020         DrawFileSlots(&LoadMenu);
1021 }
1022
1023 //---------------------------------------------------------------------------
1024 //
1025 // PROC DrawSaveMenu
1026 //
1027 //---------------------------------------------------------------------------
1028
1029 static void DrawSaveMenu(void)
1030 {
1031         MN_DrTextB("SAVE GAME", 160-MN_TextBWidth("SAVE GAME")/2, 10);
1032         if(!slottextloaded)
1033         {
1034                 MN_LoadSlotText();
1035         }
1036         DrawFileSlots(&SaveMenu);
1037 }
1038
1039 //===========================================================================
1040 //
1041 // MN_LoadSlotText
1042 //
1043 // For each slot, looks for save games and reads the description field.
1044 //
1045 //===========================================================================
1046
1047 void MN_LoadSlotText(void)
1048 {
1049         int slot;
1050         FILE *fp;
1051         char name[100];
1052         char versionText[HXS_VERSION_TEXT_LENGTH];
1053         char description[HXS_DESCRIPTION_LENGTH];
1054         boolean found;
1055
1056         for(slot = 0; slot < 6; slot++)
1057         {
1058                 found = false;
1059                 snprintf(name, 100, "%shex%d.hxs", basePath, slot);
1060                 fp = fopen(name, "rb");
1061                 if(fp)
1062                 {
1063                         fread(description, HXS_DESCRIPTION_LENGTH, 1, fp);
1064                         fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp);
1065                         fclose(fp);
1066                         if(!strcmp(versionText, HXS_VERSION_TEXT))
1067                         {
1068                                 found = true;
1069                         }
1070                 }
1071                 if(found)
1072                 {
1073                         memcpy(SlotText[slot], description, SLOTTEXTLEN);
1074                         SlotStatus[slot] = 1;
1075                 }
1076                 else
1077                 {
1078                         memset(SlotText[slot], 0, SLOTTEXTLEN);
1079                         SlotStatus[slot] = 0;
1080                 }
1081         }
1082         slottextloaded = true;
1083 }
1084
1085 //---------------------------------------------------------------------------
1086 //
1087 // PROC DrawFileSlots
1088 //
1089 //---------------------------------------------------------------------------
1090
1091 static void DrawFileSlots(Menu_t *menu)
1092 {
1093         int i;
1094         int x;
1095         int y;
1096
1097         x = menu->x;
1098         y = menu->y;
1099         for(i = 0; i < 6; i++)
1100         {
1101 #ifdef RENDER3D
1102         OGL_DrawPatch_CS(x, y, W_GetNumForName("M_FSLOT"));
1103 #else
1104                 V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE));
1105 #endif
1106                 if(SlotStatus[i])
1107                 {
1108                         MN_DrTextA(SlotText[i], x+5, y+5);
1109                 }
1110                 y += ITEM_HEIGHT;
1111         }
1112 }
1113
1114 //---------------------------------------------------------------------------
1115 //
1116 // PROC DrawOptionsMenu
1117 //
1118 //---------------------------------------------------------------------------
1119
1120 static void DrawOptionsMenu(void)
1121 {
1122 char num[5];
1123         if(messageson)
1124         {
1125                 MN_DrTextB("ON", 196, 50);
1126         }
1127         else
1128         {
1129                 MN_DrTextB("OFF", 196, 50);
1130         }
1131         MN_DrTextB(mlooktext[mouselook], 208, 110);
1132
1133         sprintf(num,"%d",mouseSensitivity);
1134         MN_DrTextB(num,265, 71); 
1135
1136         if(alwaysrun)
1137         {
1138                 MN_DrTextB("ON", 208, 130);
1139         }
1140         else
1141         {
1142                 MN_DrTextB("OFF", 208,130);
1143         }
1144 }
1145
1146 //---------------------------------------------------------------------------
1147 //
1148 // PROC DrawOptions2Menu
1149 //
1150 //---------------------------------------------------------------------------
1151
1152 static void DrawOptions2Menu(void)
1153 {
1154         DrawSlider(&Options2Menu, 1, 9, screenblocks-3);
1155         DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
1156         DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
1157         if(cdaudio == true)
1158         {
1159                 MN_DrTextB("ON", 196, 140);
1160         }
1161         else
1162         {
1163                 MN_DrTextB("OFF", 196, 140);
1164         }
1165 }
1166
1167
1168 static void DrawOptions3Menu(void)
1169 {
1170         int i;
1171
1172         for(i=0;i<15;i++)
1173         {
1174                 if(askforkey && keyaskedfor == i) {
1175                         MN_DrTextAYellow("???", 195, (i*SMALL_ITEM_HEIGHT+26));
1176                 }
1177                 else {
1178                         MN_DrTextA(Key2String(*defaults[i+FirstKey+3].location),
1179                                 195, (i*SMALL_ITEM_HEIGHT+26));
1180                 }
1181         }
1182
1183 }
1184
1185 //---------------------------------------------------------------------------
1186 //
1187 // PROC SCQuitGame
1188 //
1189 //---------------------------------------------------------------------------
1190
1191 static void SCQuitGame(int option)
1192 {
1193         MenuActive = false;
1194         askforquit = true;
1195         typeofask = 1; //quit game
1196         if(!netgame && !demoplayback)
1197         {
1198                 paused = true;
1199         }
1200 }
1201
1202 //---------------------------------------------------------------------------
1203 //
1204 // PROC SCEndGame
1205 //
1206 //---------------------------------------------------------------------------
1207
1208 static void SCEndGame(int option)
1209 {
1210         if(demoplayback)
1211         {
1212                 return;
1213         }
1214         if(SCNetCheck(3))
1215         {
1216                 MenuActive = false;
1217                 askforquit = true;
1218                 typeofask = 2; //endgame
1219                 if(!netgame && !demoplayback)
1220                 {
1221                         paused = true;
1222                 }
1223         }
1224 }
1225
1226 //---------------------------------------------------------------------------
1227 //
1228 // PROC SCMessages
1229 //
1230 //---------------------------------------------------------------------------
1231
1232 static void SCMessages(int option)
1233 {
1234         messageson ^= 1;
1235         if(messageson)
1236         {
1237                 P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
1238         }
1239         else
1240         {
1241                 P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
1242         }
1243         S_StartSound(NULL, SFX_CHAT);
1244 }
1245
1246 //===========================================================================
1247 //
1248 // SCNetCheck
1249 //
1250 //===========================================================================
1251
1252 static boolean SCNetCheck(int option)
1253 {
1254         if(!netgame)
1255         {
1256                 return true;
1257         }
1258         switch(option)
1259         {
1260                 case 1: // new game
1261                         P_SetMessage(&players[consoleplayer],
1262                                 "YOU CAN'T START A NEW GAME IN NETPLAY!", true);
1263                         break;
1264                 case 2: // load game
1265                         P_SetMessage(&players[consoleplayer],
1266                                 "YOU CAN'T LOAD A GAME IN NETPLAY!", true);
1267                         break;
1268                 case 3: // end game
1269                         P_SetMessage(&players[consoleplayer],
1270                                 "YOU CAN'T END A GAME IN NETPLAY!", true);
1271                         break;
1272         }
1273         MenuActive = false;
1274         S_StartSound(NULL, SFX_CHAT);
1275         return false;
1276 }
1277
1278 //===========================================================================
1279 //
1280 // SCNetCheck2
1281 //
1282 //===========================================================================
1283
1284 static void SCNetCheck2(int option)
1285 {
1286         SCNetCheck(option);
1287         return;
1288 }
1289
1290 //---------------------------------------------------------------------------
1291 //
1292 // PROC SCLoadGame
1293 //
1294 //---------------------------------------------------------------------------
1295
1296 static void SCLoadGame(int option)
1297 {
1298         if(!SlotStatus[option])
1299         { // Don't try to load from an empty slot
1300                 return;
1301         }
1302         G_LoadGame(option);
1303         MN_DeactivateMenu();
1304         BorderNeedRefresh = true;
1305         if(quickload == -1)
1306         {
1307                 quickload = option+1;
1308                 P_ClearMessage(&players[consoleplayer]);
1309         }
1310 }
1311
1312 //---------------------------------------------------------------------------
1313 //
1314 // PROC SCSaveGame
1315 //
1316 //---------------------------------------------------------------------------
1317
1318 static void SCSaveGame(int option)
1319 {
1320         char *ptr;
1321
1322         if(!FileMenuKeySteal)
1323         {
1324                 FileMenuKeySteal = true;
1325                 strcpy(oldSlotText, SlotText[option]);
1326                 ptr = SlotText[option];
1327                 while(*ptr)
1328                 {
1329                         ptr++;
1330                 }
1331                 *ptr = '[';
1332                 *(ptr+1) = 0;
1333                 SlotStatus[option]++;
1334                 currentSlot = option;
1335                 slotptr = ptr-SlotText[option];
1336                 return;
1337         }
1338         else
1339         {
1340                 G_SaveGame(option, SlotText[option]);
1341                 FileMenuKeySteal = false;
1342                 MN_DeactivateMenu();
1343         }
1344         BorderNeedRefresh = true;
1345         if(quicksave == -1)
1346         {
1347                 quicksave = option+1;
1348                 P_ClearMessage(&players[consoleplayer]);
1349         }
1350 }
1351
1352 //==========================================================================
1353 //
1354 // SCClass
1355 //
1356 //==========================================================================
1357
1358 static void SCClass(int option)
1359 {
1360         if(netgame)
1361         {
1362                 P_SetMessage(&players[consoleplayer],
1363                         "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!", true);
1364                 return;
1365         }
1366         MenuPClass = option;
1367         switch(MenuPClass)
1368         {
1369                 case PCLASS_FIGHTER:
1370                         SkillMenu.x = 120;
1371                         SkillItems[0].text = "SQUIRE";
1372                         SkillItems[1].text = "KNIGHT";
1373                         SkillItems[2].text = "WARRIOR";
1374                         SkillItems[3].text = "BERSERKER";
1375                         SkillItems[4].text = "TITAN";
1376                         break;
1377                 case PCLASS_CLERIC:
1378                         SkillMenu.x = 116;
1379                         SkillItems[0].text = "ALTAR BOY";
1380                         SkillItems[1].text = "ACOLYTE";
1381                         SkillItems[2].text = "PRIEST";
1382                         SkillItems[3].text = "CARDINAL";
1383                         SkillItems[4].text = "POPE";
1384                         break;
1385                 case PCLASS_MAGE:
1386                         SkillMenu.x = 112;
1387                         SkillItems[0].text = "APPRENTICE";
1388                         SkillItems[1].text = "ENCHANTER";
1389                         SkillItems[2].text = "SORCERER";
1390                         SkillItems[3].text = "WARLOCK";
1391                         SkillItems[4].text = "ARCHIMAGE";
1392                         break;
1393 #ifdef ASSASSIN
1394                 case PCLASS_ASS:
1395                         SkillMenu.x = 116;
1396                         SkillItems[0].text = "KNAVE";
1397                         SkillItems[1].text = "ROUGE";
1398                         SkillItems[2].text = "CUTTHROAT";
1399                         SkillItems[3].text = "EXECUTIONER";
1400                         SkillItems[4].text = "WIDOW MAKER";
1401                         break;
1402 #endif
1403         }
1404         SetMenu(MENU_SKILL);
1405 }
1406
1407 //---------------------------------------------------------------------------
1408 //
1409 // PROC SCSkill
1410 //
1411 //---------------------------------------------------------------------------
1412
1413 static void SCSkill(int option)
1414 {
1415         extern int SB_state;
1416
1417         PlayerClass[consoleplayer] = MenuPClass;
1418         G_DeferredNewGame(option);
1419         SB_SetClassData();
1420         SB_state = -1;
1421         MN_DeactivateMenu();
1422 }
1423
1424 //---------------------------------------------------------------------------
1425 //
1426 // PROC SCMouseSensi
1427 //
1428 //---------------------------------------------------------------------------
1429
1430 static void SCMouseSensi(int option)
1431 {
1432         if(option == RIGHT_DIR)
1433         {
1434                 if(mouseSensitivity < MENU_MAX_MOUSE_SENS)
1435                 {
1436                         mouseSensitivity++;
1437                 }
1438         }
1439         else if(mouseSensitivity)
1440         {
1441                 mouseSensitivity--;
1442         }
1443 }
1444
1445 //---------------------------------------------------------------------------
1446 //
1447 // PROC SCSfxVolume
1448 //
1449 //---------------------------------------------------------------------------
1450
1451 static void SCSfxVolume(int option)
1452 {
1453         if(option == RIGHT_DIR)
1454         {
1455                 if(snd_MaxVolume < 15)
1456                 {
1457                         snd_MaxVolume++;
1458                 }
1459         }
1460         else if(snd_MaxVolume)
1461         {
1462                 snd_MaxVolume--;
1463         }
1464         soundchanged = true; // we'll set it when we leave the menu
1465 }
1466
1467 //---------------------------------------------------------------------------
1468 //
1469 // PROC SCMusicVolume
1470 //
1471 //---------------------------------------------------------------------------
1472
1473 static void SCMusicVolume(int option)
1474 {
1475         if(option == RIGHT_DIR)
1476         {
1477                 if(snd_MusicVolume < 15)
1478                 {
1479                         snd_MusicVolume++;
1480                 }
1481         }
1482         else if(snd_MusicVolume)
1483         {
1484                 snd_MusicVolume--;
1485         }
1486         S_SetMusicVolume();
1487 }
1488
1489 //---------------------------------------------------------------------------
1490 //
1491 // PROC SCScreenSize
1492 //
1493 //---------------------------------------------------------------------------
1494
1495 static void SCScreenSize(int option)
1496 {
1497         if(option == RIGHT_DIR)
1498         {
1499                 if(screenblocks < 11)
1500                 {
1501                         screenblocks++;
1502                 }
1503         }
1504         else if(screenblocks > 3)
1505         {
1506                 screenblocks--;
1507         }
1508         R_SetViewSize(screenblocks, detailLevel);
1509 }
1510
1511 //---------------------------------------------------------------------------
1512 //
1513 // PROC SCInfo
1514 //
1515 //---------------------------------------------------------------------------
1516
1517 static void SCInfo(int option)
1518 {
1519         InfoType = 1;
1520         S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1521         if(!netgame && !demoplayback)
1522         {
1523                 paused = true;
1524         }
1525 }
1526
1527 //---------------------------------------------------------------------------
1528 //
1529 // PROC SCSetKey
1530 //
1531 //---------------------------------------------------------------------------
1532 static void SCSetKey(int option)
1533 {
1534         askforkey = true;
1535         keyaskedfor = option;
1536         if(!netgame && !demoplayback)
1537         {
1538                 paused = true;
1539         }
1540 }
1541
1542 //---------------------------------------------------------------------------
1543 //
1544 // PROC SCMouslook(int option)
1545 //
1546 //---------------------------------------------------------------------------
1547 static void SCMouselook(int option)
1548 {
1549         if(option == RIGHT_DIR)
1550         {
1551                 if(mouselook < 2) mouselook++;
1552                 
1553         }
1554         else if(mouselook) mouselook--;
1555 }
1556
1557 static void SCAlwaysRun(int option)
1558 {
1559         if(alwaysrun) alwaysrun=0;
1560         else alwaysrun=1;
1561 }
1562 static void SCCDAudio(int option)
1563 {
1564         if(cdaudio == true)
1565         {
1566                 cdaudio = false;
1567                 I_CDMusStop();
1568                 i_CDMusic = false;
1569         }
1570         else
1571         {
1572                 cdaudio = true;
1573                 ST_Message("Attempting to initialize CD Music: ");
1574                 if(!cdrom)
1575                 {
1576                         i_CDMusic = (I_CDMusInit() != -1);
1577                 }
1578                 else
1579                 { // The user is trying to use the cdrom for both game and music
1580                         i_CDMusic = false;
1581                 }
1582                 if(i_CDMusic)
1583                 {
1584                         ST_Message("initialized.\n");
1585                 }
1586                 else
1587                 {
1588                         ST_Message("failed.\n");
1589                 }
1590         }
1591 }
1592
1593 //---------------------------------------------------------------------------
1594 //
1595 // FUNC MN_Responder
1596 //
1597 //---------------------------------------------------------------------------
1598
1599 boolean MN_Responder(event_t *event)
1600 {
1601         int key;
1602         int i;
1603         MenuItem_t *item;
1604         extern boolean automapactive;
1605         static boolean shiftdown;
1606         extern void H2_StartTitle(void);
1607         extern void G_CheckDemoStatus(void);
1608         char *textBuffer;
1609
1610         if(askforkey && event->type == ev_keydown)
1611         {
1612                 ClearControls(event->data1);
1613                 *defaults[keyaskedfor+3+FirstKey].location = event->data1;
1614                 askforkey = false;
1615                 return(true);
1616         }
1617         if(askforkey && event->type == ev_mouse)
1618         {
1619                 if(event->data1&1)
1620                         mbone = defaults[keyaskedfor+3+FirstKey].location;
1621                 if(event->data1&2)
1622                         mbtwo = defaults[keyaskedfor+3+FirstKey].location;
1623                 if(event->data1&4)
1624                         mbthree = defaults[keyaskedfor+3+FirstKey].location;
1625                 else return(false);
1626                 return(true);
1627         }
1628         if(event->data1 == KEY_RSHIFT)
1629         {
1630                 shiftdown = (event->type == ev_keydown);
1631         }
1632         if(event->type != ev_keydown)
1633         {
1634                 return(false);
1635         }
1636         key = event->data1;
1637         if(InfoType)
1638         {
1639                 if(shareware)
1640                 {
1641                         InfoType = (InfoType+1)%5;
1642                 }
1643                 else
1644                 {
1645                         InfoType = (InfoType+1)%4;
1646                 }
1647                 if(key == KEY_ESCAPE)
1648                 {
1649                         InfoType = 0;
1650                 }
1651                 if(!InfoType)
1652                 {
1653                         if(!netgame && !demoplayback)
1654                         {
1655                                 paused = false;
1656                         }
1657                         MN_DeactivateMenu();
1658                         SB_state = -1; //refresh the statbar
1659                         BorderNeedRefresh = true;
1660                 }
1661                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1662                 return(true); //make the info screen eat the keypress
1663         }
1664
1665         if(ravpic && key == KEY_F1)
1666         {
1667                 G_ScreenShot();
1668                 return(true);
1669         }
1670
1671         if(askforquit)
1672         {
1673                 switch(key)
1674                 {
1675                         case 'y':
1676                                 if(askforquit)
1677                                 {
1678                                         switch(typeofask)
1679                                         {
1680                                                 case 1:
1681                                                         G_CheckDemoStatus(); 
1682                                                         I_Quit();
1683                                                         break;
1684                                                 case 2:
1685                                                         P_ClearMessage(&players[consoleplayer]);
1686                                                         typeofask = 0;
1687                                                         askforquit = false;
1688                                                         paused = false;
1689                                                         I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
1690                                                         H2_StartTitle(); // go to intro/demo mode.
1691                                                         break;
1692                                                 case 3:
1693                                                         P_SetMessage(&players[consoleplayer], 
1694                                                                 "QUICKSAVING....", false);
1695                                                         FileMenuKeySteal = true;
1696                                                         SCSaveGame(quicksave-1);
1697                                                         askforquit = false;
1698                                                         typeofask = 0;
1699                                                         BorderNeedRefresh = true;
1700                                                         return true;
1701                                                 case 4:
1702                                                         P_SetMessage(&players[consoleplayer], 
1703                                                                 "QUICKLOADING....", false);
1704                                                         SCLoadGame(quickload-1);
1705                                                         askforquit = false;
1706                                                         typeofask = 0;
1707                                                         BorderNeedRefresh = true;
1708                                                         return true;
1709                                                 case 5:
1710                                                         askforquit = false;
1711                                                         typeofask = 0;  
1712                                                         BorderNeedRefresh = true;
1713                                                         mn_SuicideConsole = true;
1714                                                         return true;
1715                                                         break;
1716                                                 default:
1717                                                         return true; // eat the 'y' keypress
1718                                         }
1719                                 }
1720                                 return false;
1721                         case 'n':
1722                         case KEY_ESCAPE:
1723                                 if(askforquit)
1724                                 {
1725                                         players[consoleplayer].messageTics = 0;
1726                                         askforquit = false;
1727                                         typeofask = 0;
1728                                         paused = false;
1729                                         UpdateState |= I_FULLSCRN;
1730                                         BorderNeedRefresh = true;
1731                                         return true;
1732                                 }
1733                                 return false;
1734                 }
1735                 return false; // don't let the keys filter thru
1736         }
1737         if(MenuActive == false && !chatmodeon)
1738         {
1739                 switch(key)
1740                 {
1741                         case KEY_MINUS:
1742                                 if(automapactive)
1743                                 { // Don't screen size in automap
1744                                         return(false);
1745                                 }
1746                                 SCScreenSize(LEFT_DIR);
1747                                 S_StartSound(NULL, SFX_PICKUP_KEY);
1748                                 BorderNeedRefresh = true;
1749                                 UpdateState |= I_FULLSCRN;
1750                                 return(true);
1751                         case KEY_EQUALS:
1752                                 if(automapactive)
1753                                 { // Don't screen size in automap
1754                                         return(false);
1755                                 }
1756                                 SCScreenSize(RIGHT_DIR);
1757                                 S_StartSound(NULL, SFX_PICKUP_KEY);
1758                                 BorderNeedRefresh = true;
1759                                 UpdateState |= I_FULLSCRN;
1760                                 return(true);
1761 #ifdef __NeXT__
1762                         case 'q':
1763                                 MenuActive = false;
1764                                 askforquit = true;
1765                                 typeofask = 5; // suicide
1766                                 return true;
1767 #endif
1768 #ifndef __NeXT__
1769                         case KEY_F1: // help screen
1770                                 SCInfo(0); // start up info screens
1771                                 MenuActive = true;
1772                                 return(true);
1773                         case KEY_F2: // save game
1774                                 if(gamestate == GS_LEVEL && !demoplayback)
1775                                 {
1776                                         MenuActive = true;
1777                                         FileMenuKeySteal = false;
1778                                         MenuTime = 0;
1779                                         CurrentMenu = &SaveMenu;
1780                                         CurrentItPos = CurrentMenu->oldItPos;
1781                                         if(!netgame && !demoplayback)
1782                                         {
1783                                                 paused = true;
1784                                         }
1785                                         S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1786                                         slottextloaded = false; //reload the slot text, when needed
1787                                 }
1788                                 return true;
1789                         case KEY_F3: // load game
1790                                 if(SCNetCheck(2))
1791                                 {
1792                                         MenuActive = true;
1793                                         FileMenuKeySteal = false;
1794                                         MenuTime = 0;
1795                                         CurrentMenu = &LoadMenu;
1796                                         CurrentItPos = CurrentMenu->oldItPos;
1797                                         if(!netgame && !demoplayback)
1798                                         {
1799                                                 paused = true;
1800                                         }
1801                                         S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1802                                         slottextloaded = false; //reload the slot text, when needed
1803                                 }
1804                                 return true;
1805                         case KEY_F4: // volume
1806                                 MenuActive = true;
1807                                 FileMenuKeySteal = false;
1808                                 MenuTime = 0;
1809                                 CurrentMenu = &Options2Menu;
1810                                 CurrentItPos = CurrentMenu->oldItPos;
1811                                 if(!netgame && !demoplayback)
1812                                 {
1813                                         paused = true;
1814                                 }
1815                                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1816                                 slottextloaded = false; //reload the slot text, when needed
1817                                 return true;
1818                         case KEY_F5:
1819                                 MenuActive = false;
1820                                 askforquit = true;
1821                                 typeofask = 5; // suicide
1822                                 return true;
1823                         case KEY_F6: // quicksave
1824                                 if(gamestate == GS_LEVEL && !demoplayback)
1825                                 {
1826                                         if(!quicksave || quicksave == -1)
1827                                         {
1828                                                 MenuActive = true;
1829                                                 FileMenuKeySteal = false;
1830                                                 MenuTime = 0;
1831                                                 CurrentMenu = &SaveMenu;
1832                                                 CurrentItPos = CurrentMenu->oldItPos;
1833                                                 if(!netgame && !demoplayback)
1834                                                 {
1835                                                         paused = true;
1836                                                 }
1837                                                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1838                                                 slottextloaded = false; //reload the slot text
1839                                                 quicksave = -1;
1840                                                 P_SetMessage(&players[consoleplayer],
1841                                                         "CHOOSE A QUICKSAVE SLOT", true);
1842                                         }
1843                                         else
1844                                         {
1845                                                 askforquit = true;
1846                                                 typeofask = 3;
1847                                                 if(!netgame && !demoplayback)
1848                                                 {
1849                                                         paused = true;
1850                                                 }
1851                                                 S_StartSound(NULL, SFX_CHAT);
1852                                         }
1853                                 }
1854                                 return true;
1855                         case KEY_F7: // endgame
1856                                 if(SCNetCheck(3))
1857                                 {
1858                                         if(gamestate == GS_LEVEL && !demoplayback)
1859                                         {
1860                                                 S_StartSound(NULL, SFX_CHAT);
1861                                                 SCEndGame(0);
1862                                         }
1863                                 }
1864                                 return true;
1865                         case KEY_F8: // toggle messages
1866                                 SCMessages(0);
1867                                 return true;
1868                         case KEY_F9: // quickload
1869                                 if(SCNetCheck(2))
1870                                 {
1871                                         if(!quickload || quickload == -1)
1872                                         {
1873                                                 MenuActive = true;
1874                                                 FileMenuKeySteal = false;
1875                                                 MenuTime = 0;
1876                                                 CurrentMenu = &LoadMenu;
1877                                                 CurrentItPos = CurrentMenu->oldItPos;
1878                                                 if(!netgame && !demoplayback)
1879                                                 {
1880                                                         paused = true;
1881                                                 }
1882                                                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1883                                                 slottextloaded = false; // reload the slot text
1884                                                 quickload = -1;
1885                                                 P_SetMessage(&players[consoleplayer],
1886                                                         "CHOOSE A QUICKLOAD SLOT", true);
1887                                         }
1888                                         else
1889                                         {
1890                                                 askforquit = true;
1891                                                 if(!netgame && !demoplayback)
1892                                                 {
1893                                                         paused = true;
1894                                                 }
1895                                                 typeofask = 4;
1896                                                 S_StartSound(NULL, SFX_CHAT);
1897                                         }
1898                                 }
1899                                 return true;
1900                         case KEY_F10: // quit
1901                                 if(gamestate == GS_LEVEL || gamestate == GS_FINALE)
1902                                 {
1903                                         SCQuitGame(0);
1904                                         S_StartSound(NULL, SFX_CHAT);
1905                                 }
1906                                 return true;
1907                         case KEY_F11: // F11 - gamma mode correction
1908                                 usegamma++;
1909                                 if(usegamma > 4)
1910                                 {
1911                                         usegamma = 0;
1912                                 }
1913                                 SB_PaletteFlash(true); // force change
1914                                 P_SetMessage(&players[consoleplayer], GammaText[usegamma],
1915                                         false);
1916                                 return true;
1917                         case KEY_F12: // F12 - reload current map (devmaps mode)
1918                                 if(netgame || DevMaps == false)
1919                                 {
1920                                         return false;
1921                                 }
1922                                 if(gamekeydown[key_speed])
1923                                 { // Monsters ON
1924                                         nomonsters = false;
1925                                 }
1926                                 if(gamekeydown[key_strafe])
1927                                 { // Monsters OFF
1928                                         nomonsters = true;
1929                                 }
1930                                 G_DeferedInitNew(gameskill, gameepisode, gamemap);
1931                                 P_SetMessage(&players[consoleplayer], TXT_CHEATWARP,
1932                                         false);
1933                                 return true;
1934 #endif
1935                 }
1936
1937         }
1938
1939         if(MenuActive == false)
1940         {
1941                 if(key == KEY_ESCAPE || gamestate == GS_DEMOSCREEN || demoplayback)
1942                 {
1943                         MN_ActivateMenu();
1944                         return(true);
1945                 }
1946                 return(false);
1947         }
1948         if(!FileMenuKeySteal)
1949         {
1950                 item = &CurrentMenu->items[CurrentItPos];
1951                 switch(key)
1952                 {
1953                         case KEY_DOWNARROW:
1954                                 do
1955                                 {
1956 if(CurrentMenu->items[CurrentItPos].type == ITT_SETKEY && CurrentItPos+1 > CurrentMenu->itemCount-1)
1957         {
1958                 if(FirstKey == 5) 
1959                 {
1960                         CurrentItPos = 0;  //End of Key menu
1961                         FirstKey = 0;
1962                 }
1963                 else
1964                 {
1965                         FirstKey++;
1966                 }       
1967         }
1968         else if(CurrentItPos+1 > CurrentMenu->itemCount-1)
1969         {
1970                 CurrentItPos = 0;
1971         }
1972         else
1973         {
1974                 CurrentItPos++;
1975         }
1976 } while(CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
1977 S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
1978 return(true);
1979 break;
1980 case KEY_UPARROW:
1981         do
1982         {
1983         if(CurrentMenu->items[CurrentItPos].type == ITT_SETKEY && CurrentItPos==0)
1984         {
1985                 if(FirstKey == 0) 
1986                 {
1987                         CurrentItPos = 14;  //End of Key menu
1988                         FirstKey = 5;
1989                 }
1990                 else
1991                 {
1992                         FirstKey--;
1993                 }       
1994         }
1995         else if(CurrentItPos == 0)
1996                                         {
1997                                                 CurrentItPos = CurrentMenu->itemCount-1;
1998                                         }
1999                                         else
2000                                         {
2001                                                 CurrentItPos--;
2002                                         }
2003                                 } while(CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
2004                                 S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
2005                                 return(true);
2006                                 break;
2007                         case KEY_LEFTARROW:
2008                                 if(item->type == ITT_LRFUNC && item->func != NULL)
2009                                 {
2010                                         item->func(LEFT_DIR);
2011                                         S_StartSound(NULL, SFX_PICKUP_KEY);
2012                                 }
2013                                 return(true);
2014                                 break;
2015                         case KEY_RIGHTARROW:
2016                                 if(item->type == ITT_LRFUNC && item->func != NULL)
2017                                 {
2018                                         item->func(RIGHT_DIR);
2019                                         S_StartSound(NULL, SFX_PICKUP_KEY);
2020                                 }
2021                                 return(true);
2022                                 break;
2023                         case KEY_ENTER:
2024                                 if(item->type == ITT_SETMENU)
2025                                 {
2026                                         if(item->func != NULL)  
2027                                         {
2028                                                 item->func(item->option);
2029                                         }
2030                                         SetMenu(item->menu);
2031                                 }
2032                                 else if(item->func != NULL)
2033                                 {
2034                                         CurrentMenu->oldItPos = CurrentItPos;
2035                                         if(item->type == ITT_LRFUNC)
2036                                         {
2037                                                 item->func(RIGHT_DIR);
2038                                         }
2039                                         else if(item->type == ITT_EFUNC)
2040                                         {
2041                                                 item->func(item->option);
2042                                         }
2043                                         else if(item->type == ITT_SETKEY)
2044                                         {
2045                                                 item->func(item->option);
2046                                         }
2047                                 }
2048                                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
2049                                 return(true);
2050                                 break;
2051                         case KEY_ESCAPE:
2052                                 MN_DeactivateMenu();
2053                                 return(true);
2054                         case KEY_BACKSPACE:
2055                                 S_StartSound(NULL, SFX_PICKUP_KEY);
2056                                 if(CurrentMenu->prevMenu == MENU_NONE)
2057                                 {
2058                                         MN_DeactivateMenu();
2059                                 }
2060                                 else
2061                                 {
2062                                         SetMenu(CurrentMenu->prevMenu);
2063                                 }
2064                                 return(true);
2065                         default:
2066                                 for(i = 0; i < CurrentMenu->itemCount; i++)
2067                                 {
2068                                         if(CurrentMenu->items[i].text)
2069                                         {
2070                                                 if(toupper(key)
2071                                                         == toupper(CurrentMenu->items[i].text[0]))
2072                                                 {
2073                                                         CurrentItPos = i;
2074                                                         return(true);
2075                                                 }
2076                                         }
2077                                 }
2078                                 break;
2079                 }
2080                 return(false);
2081         }
2082         else
2083         { // Editing file names
2084                 textBuffer = &SlotText[currentSlot][slotptr];
2085                 if(key == KEY_BACKSPACE)
2086                 {
2087                         if(slotptr)
2088                         {
2089                                 *textBuffer-- = 0;
2090                                 *textBuffer = ASCII_CURSOR;
2091                                 slotptr--;
2092                         }
2093                         return(true);
2094                 }
2095                 if(key == KEY_ESCAPE)
2096                 {
2097                         memset(SlotText[currentSlot], 0, SLOTTEXTLEN+2);
2098                         strcpy(SlotText[currentSlot], oldSlotText);
2099                         SlotStatus[currentSlot]--;
2100                         MN_DeactivateMenu();
2101                         return(true);
2102                 }
2103                 if(key == KEY_ENTER)
2104                 {
2105                         SlotText[currentSlot][slotptr] = 0; // clear the cursor
2106                         item = &CurrentMenu->items[CurrentItPos];
2107                         CurrentMenu->oldItPos = CurrentItPos;
2108                         if(item->type == ITT_EFUNC)
2109                         {
2110                                 item->func(item->option);
2111                                 if(item->menu != MENU_NONE)
2112                                 {
2113                                         SetMenu(item->menu);
2114                                 }
2115                         }
2116                         return(true);
2117                 }
2118                 if(slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
2119                 {
2120                         if((key >= 'a' && key <= 'z'))
2121                         {
2122                                 *textBuffer++ = key-32;
2123                                 *textBuffer = ASCII_CURSOR;
2124                                 slotptr++;
2125                                 return(true);
2126                         }
2127                         if(((key >= '0' && key <= '9') || key == ' '
2128                                 || key == ',' || key == '.' || key == '-')
2129                                 && !shiftdown)
2130                         {
2131                                 *textBuffer++ = key;
2132                                 *textBuffer = ASCII_CURSOR;
2133                                 slotptr++;
2134                                 return(true);
2135                         }
2136                         if(shiftdown && key == '1')
2137                         {
2138                                 *textBuffer++ = '!';
2139                                 *textBuffer = ASCII_CURSOR;
2140                                 slotptr++;
2141                                 return(true);
2142                         }
2143                 }
2144                 return(true);
2145         }
2146         return(false);
2147 }
2148
2149 //---------------------------------------------------------------------------
2150 //
2151 // PROC MN_ActivateMenu
2152 //
2153 //---------------------------------------------------------------------------
2154
2155 void MN_ActivateMenu(void)
2156 {
2157         if(MenuActive)
2158         {
2159                 return;
2160         }
2161         if(paused)
2162         {
2163                 S_ResumeSound();
2164         }
2165         MenuActive = true;
2166         FileMenuKeySteal = false;
2167         MenuTime = 0;
2168         CurrentMenu = &MainMenu;
2169         CurrentItPos = CurrentMenu->oldItPos;
2170         if(!netgame && !demoplayback)
2171         {
2172                 paused = true;
2173         }
2174         S_StartSound(NULL, SFX_PLATFORM_STOP);
2175         slottextloaded = false; //reload the slot text, when needed
2176 }
2177
2178 //---------------------------------------------------------------------------
2179 //
2180 // PROC MN_DeactivateMenu
2181 //
2182 //---------------------------------------------------------------------------
2183
2184 void MN_DeactivateMenu(void)
2185 {
2186         CurrentMenu->oldItPos = CurrentItPos;
2187         MenuActive = false;
2188         if(!netgame)
2189         {
2190                 paused = false;
2191         }
2192         S_StartSound(NULL, SFX_PLATFORM_STOP);
2193         P_ClearMessage(&players[consoleplayer]);
2194 }
2195
2196 //---------------------------------------------------------------------------
2197 //
2198 // PROC MN_DrawInfo
2199 //
2200 //---------------------------------------------------------------------------
2201
2202 void MN_DrawInfo(void)
2203 {
2204 #ifdef RENDER3D
2205     OGL_SetFilter( 0 );
2206     OGL_DrawRawScreen( W_GetNumForName("TITLE")+InfoType );
2207 #else
2208         I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
2209         memcpy(screen, (byte *)W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType,
2210                 PU_CACHE), SCREENWIDTH*SCREENHEIGHT);
2211 //      V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType,
2212 //              PU_CACHE));
2213 #endif
2214 }
2215
2216
2217 //---------------------------------------------------------------------------
2218 //
2219 // PROC SetMenu
2220 //
2221 //---------------------------------------------------------------------------
2222
2223 static void SetMenu(MenuType_t menu)
2224 {
2225         CurrentMenu->oldItPos = CurrentItPos;
2226         CurrentMenu = Menus[menu];
2227         CurrentItPos = CurrentMenu->oldItPos;
2228 }
2229
2230 //---------------------------------------------------------------------------
2231 //
2232 // PROC DrawSlider
2233 //
2234 //---------------------------------------------------------------------------
2235
2236 static void DrawSlider(Menu_t *menu, int item, int width, int slot)
2237 {
2238         int x;
2239         int y;
2240         int x2;
2241         int count;
2242
2243         x = menu->x+24;
2244         y = menu->y+2+(item*ITEM_HEIGHT);
2245
2246 #ifdef RENDER3D
2247     OGL_DrawPatch_CS(x-32, y, W_GetNumForName("M_SLDLT"));
2248     for(x2 = x, count = width; count--; x2 += 8)
2249     {
2250         OGL_DrawPatch_CS( x2, y, W_GetNumForName(count&1 ? "M_SLDMD1" :
2251                           "M_SLDMD2") );
2252     }
2253     OGL_DrawPatch_CS(x2, y, W_GetNumForName("M_SLDRT"));
2254     OGL_DrawPatch_CS(x+4+slot*8, y+7, W_GetNumForName("M_SLDKB"));
2255 #else
2256         V_DrawPatch(x-32, y, W_CacheLumpName("M_SLDLT", PU_CACHE));
2257         for(x2 = x, count = width; count--; x2 += 8)
2258         {
2259                 V_DrawPatch(x2, y, W_CacheLumpName(count&1 ? "M_SLDMD1"
2260                         : "M_SLDMD2", PU_CACHE));
2261         }
2262         V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE));
2263         V_DrawPatch(x+4+slot*8, y+7, W_CacheLumpName("M_SLDKB", PU_CACHE));
2264 #endif
2265 }
2266