1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 
18 // HEADER FILES ------------------------------------------------------------
19 
20 #include <ctype.h>
21 #include "h2def.h"
22 #include "doomkeys.h"
23 #include "i_input.h"
24 #include "i_system.h"
25 #include "i_swap.h"
26 #include "i_video.h"
27 #include "m_controls.h"
28 #include "m_misc.h"
29 #include "p_local.h"
30 #include "r_local.h"
31 #include "s_sound.h"
32 #include "v_video.h"
33 
34 // MACROS ------------------------------------------------------------------
35 
36 #define LEFT_DIR 0
37 #define RIGHT_DIR 1
38 #define ITEM_HEIGHT 20
39 #define SELECTOR_XOFFSET (-28)
40 #define SELECTOR_YOFFSET (-1)
41 #define SLOTTEXTLEN	16
42 #define ASCII_CURSOR '['
43 
44 // TYPES -------------------------------------------------------------------
45 
46 typedef enum
47 {
48     ITT_EMPTY,
49     ITT_EFUNC,
50     ITT_LRFUNC,
51     ITT_SETMENU,
52     ITT_INERT
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_FILES,
63     MENU_LOAD,
64     MENU_SAVE,
65     MENU_NONE
66 } MenuType_t;
67 
68 typedef struct
69 {
70     ItemType_t type;
71     const char *text;
72     void (*func) (int option);
73     int option;
74     MenuType_t menu;
75 } MenuItem_t;
76 
77 typedef struct
78 {
79     int x;
80     int y;
81     void (*drawFunc) (void);
82     int itemCount;
83     MenuItem_t *items;
84     int oldItPos;
85     MenuType_t prevMenu;
86 } Menu_t;
87 
88 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
89 
90 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
91 
92 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
93 
94 static void InitFonts(void);
95 static void SetMenu(MenuType_t menu);
96 static void SCQuitGame(int option);
97 static void SCClass(int option);
98 static void SCSkill(int option);
99 static void SCMouseSensi(int option);
100 static void SCSfxVolume(int option);
101 static void SCMusicVolume(int option);
102 static void SCScreenSize(int option);
103 static boolean SCNetCheck(int option);
104 static void SCNetCheck2(int option);
105 static void SCLoadGame(int option);
106 static void SCSaveGame(int option);
107 static void SCMessages(int option);
108 static void SCEndGame(int option);
109 static void SCInfo(int option);
110 static void DrawMainMenu(void);
111 static void DrawClassMenu(void);
112 static void DrawSkillMenu(void);
113 static void DrawOptionsMenu(void);
114 static void DrawOptions2Menu(void);
115 static void DrawFileSlots(Menu_t * menu);
116 static void DrawFilesMenu(void);
117 static void MN_DrawInfo(void);
118 static void DrawLoadMenu(void);
119 static void DrawSaveMenu(void);
120 static void DrawSlider(Menu_t * menu, int item, int width, int slot);
121 void MN_LoadSlotText(void);
122 
123 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
124 
125 extern int detailLevel;
126 extern boolean gamekeydown[256];        // The NUMKEYS macro is local to g_game
127 
128 // PUBLIC DATA DEFINITIONS -------------------------------------------------
129 
130 boolean MenuActive;
131 int InfoType;
132 int messageson = true;
133 boolean mn_SuicideConsole;
134 
135 // PRIVATE DATA DEFINITIONS ------------------------------------------------
136 
137 static int FontABaseLump;
138 static int FontAYellowBaseLump;
139 static int FontBBaseLump;
140 static int MauloBaseLump;
141 static Menu_t *CurrentMenu;
142 static int CurrentItPos;
143 static int MenuPClass;
144 static int MenuTime;
145 static boolean soundchanged;
146 
147 boolean askforquit;
148 static int typeofask;
149 static boolean FileMenuKeySteal;
150 static boolean slottextloaded;
151 static char SlotText[6][SLOTTEXTLEN + 2];
152 static char oldSlotText[SLOTTEXTLEN + 2];
153 static int SlotStatus[6];
154 static int slotptr;
155 static int currentSlot;
156 static int quicksave;
157 static int quickload;
158 
159 static MenuItem_t MainItems[] = {
160     {ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS},
161     {ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS},
162     {ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES},
163     {ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE},
164     {ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE}
165 };
166 
167 static Menu_t MainMenu = {
168     110, 56,
169     DrawMainMenu,
170     5, MainItems,
171     0,
172     MENU_NONE
173 };
174 
175 static MenuItem_t ClassItems[] = {
176     {ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE},
177     {ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE},
178     {ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE}
179 };
180 
181 static Menu_t ClassMenu = {
182     66, 66,
183     DrawClassMenu,
184     3, ClassItems,
185     0,
186     MENU_MAIN
187 };
188 
189 static MenuItem_t FilesItems[] = {
190     {ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD},
191     {ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE}
192 };
193 
194 static Menu_t FilesMenu = {
195     110, 60,
196     DrawFilesMenu,
197     2, FilesItems,
198     0,
199     MENU_MAIN
200 };
201 
202 static MenuItem_t LoadItems[] = {
203     {ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE},
204     {ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE},
205     {ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE},
206     {ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE},
207     {ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE},
208     {ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE}
209 };
210 
211 static Menu_t LoadMenu = {
212     70, 30,
213     DrawLoadMenu,
214     6, LoadItems,
215     0,
216     MENU_FILES
217 };
218 
219 static MenuItem_t SaveItems[] = {
220     {ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE},
221     {ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE},
222     {ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE},
223     {ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE},
224     {ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE},
225     {ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE}
226 };
227 
228 static Menu_t SaveMenu = {
229     70, 30,
230     DrawSaveMenu,
231     6, SaveItems,
232     0,
233     MENU_FILES
234 };
235 
236 static MenuItem_t SkillItems[] = {
237     {ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE},
238     {ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE},
239     {ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE},
240     {ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE},
241     {ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE}
242 };
243 
244 static Menu_t SkillMenu = {
245     120, 44,
246     DrawSkillMenu,
247     5, SkillItems,
248     2,
249     MENU_CLASS
250 };
251 
252 static MenuItem_t OptionsItems[] = {
253     {ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE},
254     {ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE},
255     {ITT_LRFUNC, "MOUSE SENSITIVITY", SCMouseSensi, 0, MENU_NONE},
256     {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
257     {ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2}
258 };
259 
260 static Menu_t OptionsMenu = {
261     88, 30,
262     DrawOptionsMenu,
263     5, OptionsItems,
264     0,
265     MENU_MAIN
266 };
267 
268 static MenuItem_t Options2Items[] = {
269     {ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE},
270     {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
271     {ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE},
272     {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
273     {ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE},
274     {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}
275 };
276 
277 static Menu_t Options2Menu = {
278     90, 20,
279     DrawOptions2Menu,
280     6, Options2Items,
281     0,
282     MENU_OPTIONS
283 };
284 
285 static Menu_t *Menus[] = {
286     &MainMenu,
287     &ClassMenu,
288     &SkillMenu,
289     &OptionsMenu,
290     &Options2Menu,
291     &FilesMenu,
292     &LoadMenu,
293     &SaveMenu
294 };
295 
296 // [crispy] intermediate gamma levels
297 static const char *GammaText[] = {
298     TXT_GAMMA_LEVEL_OFF,
299     TXT_GAMMA_LEVEL_05,
300     TXT_GAMMA_LEVEL_1,
301     TXT_GAMMA_LEVEL_15,
302     TXT_GAMMA_LEVEL_2,
303     TXT_GAMMA_LEVEL_25,
304     TXT_GAMMA_LEVEL_3,
305     TXT_GAMMA_LEVEL_35,
306     TXT_GAMMA_LEVEL_4
307 };
308 
309 // CODE --------------------------------------------------------------------
310 
311 //---------------------------------------------------------------------------
312 //
313 // PROC MN_Init
314 //
315 //---------------------------------------------------------------------------
316 
MN_Init(void)317 void MN_Init(void)
318 {
319     InitFonts();
320     MenuActive = false;
321 //      messageson = true;              // Set by defaults in .CFG
322     MauloBaseLump = W_GetNumForName("FBULA0");  // ("M_SKL00");
323 }
324 
325 //---------------------------------------------------------------------------
326 //
327 // PROC InitFonts
328 //
329 //---------------------------------------------------------------------------
330 
InitFonts(void)331 static void InitFonts(void)
332 {
333     FontABaseLump = W_GetNumForName("FONTA_S") + 1;
334     FontAYellowBaseLump = W_GetNumForName("FONTAY_S") + 1;
335     FontBBaseLump = W_GetNumForName("FONTB_S") + 1;
336 }
337 
338 //---------------------------------------------------------------------------
339 //
340 // PROC MN_DrTextA
341 //
342 // Draw text using font A.
343 //
344 //---------------------------------------------------------------------------
345 
MN_DrTextA(const char * text,int x,int y)346 void MN_DrTextA(const char *text, int x, int y)
347 {
348     char c;
349     patch_t *p;
350 
351     while ((c = *text++) != 0)
352     {
353         if (c < 33)
354         {
355             x += 5;
356         }
357         else
358         {
359             p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
360             V_DrawPatch(x, y, p);
361             x += SHORT(p->width) - 1;
362         }
363     }
364 }
365 
366 //==========================================================================
367 //
368 // MN_DrTextAYellow
369 //
370 //==========================================================================
371 
MN_DrTextAYellow(const char * text,int x,int y)372 void MN_DrTextAYellow(const char *text, int x, int y)
373 {
374     char c;
375     patch_t *p;
376 
377     while ((c = *text++) != 0)
378     {
379         if (c < 33)
380         {
381             x += 5;
382         }
383         else
384         {
385             p = W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE);
386             V_DrawPatch(x, y, p);
387             x += SHORT(p->width) - 1;
388         }
389     }
390 }
391 
392 //---------------------------------------------------------------------------
393 //
394 // FUNC MN_TextAWidth
395 //
396 // Returns the pixel width of a string using font A.
397 //
398 //---------------------------------------------------------------------------
399 
MN_TextAWidth(const char * text)400 int MN_TextAWidth(const char *text)
401 {
402     char c;
403     int width;
404     patch_t *p;
405 
406     width = 0;
407     while ((c = *text++) != 0)
408     {
409         if (c < 33)
410         {
411             width += 5;
412         }
413         else
414         {
415             p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
416             width += SHORT(p->width) - 1;
417         }
418     }
419     return (width);
420 }
421 
422 //---------------------------------------------------------------------------
423 //
424 // PROC MN_DrTextB
425 //
426 // Draw text using font B.
427 //
428 //---------------------------------------------------------------------------
429 
MN_DrTextB(const char * text,int x,int y)430 void MN_DrTextB(const char *text, int x, int y)
431 {
432     char c;
433     patch_t *p;
434 
435     while ((c = *text++) != 0)
436     {
437         if (c < 33)
438         {
439             x += 8;
440         }
441         else
442         {
443             p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
444             V_DrawPatch(x, y, p);
445             x += SHORT(p->width) - 1;
446         }
447     }
448 }
449 
450 //---------------------------------------------------------------------------
451 //
452 // FUNC MN_TextBWidth
453 //
454 // Returns the pixel width of a string using font B.
455 //
456 //---------------------------------------------------------------------------
457 
MN_TextBWidth(const char * text)458 int MN_TextBWidth(const char *text)
459 {
460     char c;
461     int width;
462     patch_t *p;
463 
464     width = 0;
465     while ((c = *text++) != 0)
466     {
467         if (c < 33)
468         {
469             width += 5;
470         }
471         else
472         {
473             p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
474             width += SHORT(p->width) - 1;
475         }
476     }
477     return (width);
478 }
479 
480 //---------------------------------------------------------------------------
481 //
482 // PROC MN_Ticker
483 //
484 //---------------------------------------------------------------------------
485 
MN_Ticker(void)486 void MN_Ticker(void)
487 {
488     if (MenuActive == false)
489     {
490         return;
491     }
492     MenuTime++;
493 }
494 
495 //---------------------------------------------------------------------------
496 //
497 // PROC MN_Drawer
498 //
499 //---------------------------------------------------------------------------
500 
501 const char *QuitEndMsg[] = {
502     "ARE YOU SURE YOU WANT TO QUIT?",
503     "ARE YOU SURE YOU WANT TO END THE GAME?",
504     "DO YOU WANT TO QUICKSAVE THE GAME NAMED",
505     "DO YOU WANT TO QUICKLOAD THE GAME NAMED",
506     "ARE YOU SURE YOU WANT TO SUICIDE?"
507 };
508 
MN_Drawer(void)509 void MN_Drawer(void)
510 {
511     int i;
512     int x;
513     int y;
514     MenuItem_t *item;
515     const char *selName;
516 
517     if (MenuActive == false)
518     {
519         if (askforquit)
520         {
521             MN_DrTextA(QuitEndMsg[typeofask - 1], 160 -
522                        MN_TextAWidth(QuitEndMsg[typeofask - 1]) / 2, 80);
523             if (typeofask == 3)
524             {
525                 MN_DrTextA(SlotText[quicksave - 1], 160 -
526                            MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
527                 MN_DrTextA("?", 160 +
528                            MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
529             }
530             if (typeofask == 4)
531             {
532                 MN_DrTextA(SlotText[quickload - 1], 160 -
533                            MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
534                 MN_DrTextA("?", 160 +
535                            MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
536             }
537             UpdateState |= I_FULLSCRN;
538         }
539         return;
540     }
541     else
542     {
543         UpdateState |= I_FULLSCRN;
544         if (InfoType)
545         {
546             MN_DrawInfo();
547             return;
548         }
549         if (screenblocks < 10)
550         {
551             BorderNeedRefresh = true;
552         }
553         if (CurrentMenu->drawFunc != NULL)
554         {
555             CurrentMenu->drawFunc();
556         }
557         x = CurrentMenu->x;
558         y = CurrentMenu->y;
559         item = CurrentMenu->items;
560         for (i = 0; i < CurrentMenu->itemCount; i++)
561         {
562             if (item->type != ITT_EMPTY && item->text)
563             {
564                 MN_DrTextB(item->text, x, y);
565             }
566             y += ITEM_HEIGHT;
567             item++;
568         }
569         y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET;
570         selName = MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2";
571         V_DrawPatch(x + SELECTOR_XOFFSET, y,
572                     W_CacheLumpName(selName, PU_CACHE));
573     }
574 }
575 
576 //---------------------------------------------------------------------------
577 //
578 // PROC DrawMainMenu
579 //
580 //---------------------------------------------------------------------------
581 
DrawMainMenu(void)582 static void DrawMainMenu(void)
583 {
584     int frame;
585 
586     frame = (MenuTime / 5) % 7;
587     V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE));
588 // Old Gold skull positions: (40, 10) and (232, 10)
589     V_DrawPatch(37, 80, W_CacheLumpNum(MauloBaseLump + (frame + 2) % 7,
590                                        PU_CACHE));
591     V_DrawPatch(278, 80, W_CacheLumpNum(MauloBaseLump + frame, PU_CACHE));
592 }
593 
594 //==========================================================================
595 //
596 // DrawClassMenu
597 //
598 //==========================================================================
599 
DrawClassMenu(void)600 static void DrawClassMenu(void)
601 {
602     pclass_t class;
603     static const char *boxLumpName[3] = {
604         "m_fbox",
605         "m_cbox",
606         "m_mbox"
607     };
608     static const char *walkLumpName[3] = {
609         "m_fwalk1",
610         "m_cwalk1",
611         "m_mwalk1"
612     };
613 
614     MN_DrTextB("CHOOSE CLASS:", 34, 24);
615     class = (pclass_t) CurrentMenu->items[CurrentItPos].option;
616     V_DrawPatch(174, 8, W_CacheLumpName(boxLumpName[class], PU_CACHE));
617     V_DrawPatch(174 + 24, 8 + 12,
618                 W_CacheLumpNum(W_GetNumForName(walkLumpName[class])
619                                + ((MenuTime >> 3) & 3), PU_CACHE));
620 }
621 
622 //---------------------------------------------------------------------------
623 //
624 // PROC DrawSkillMenu
625 //
626 //---------------------------------------------------------------------------
627 
DrawSkillMenu(void)628 static void DrawSkillMenu(void)
629 {
630     MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16);
631 }
632 
633 //---------------------------------------------------------------------------
634 //
635 // PROC DrawFilesMenu
636 //
637 //---------------------------------------------------------------------------
638 
DrawFilesMenu(void)639 static void DrawFilesMenu(void)
640 {
641 // clear out the quicksave/quickload stuff
642     quicksave = 0;
643     quickload = 0;
644     P_ClearMessage(&players[consoleplayer]);
645 }
646 
647 //---------------------------------------------------------------------------
648 //
649 // PROC DrawLoadMenu
650 //
651 //---------------------------------------------------------------------------
652 
DrawLoadMenu(void)653 static void DrawLoadMenu(void)
654 {
655     MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 10);
656     if (!slottextloaded)
657     {
658         MN_LoadSlotText();
659     }
660     DrawFileSlots(&LoadMenu);
661 }
662 
663 //---------------------------------------------------------------------------
664 //
665 // PROC DrawSaveMenu
666 //
667 //---------------------------------------------------------------------------
668 
DrawSaveMenu(void)669 static void DrawSaveMenu(void)
670 {
671     MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 10);
672     if (!slottextloaded)
673     {
674         MN_LoadSlotText();
675     }
676     DrawFileSlots(&SaveMenu);
677 }
678 
ReadDescriptionForSlot(int slot,char * description)679 static boolean ReadDescriptionForSlot(int slot, char *description)
680 {
681     FILE *fp;
682     boolean found;
683     char name[100];
684     char versionText[HXS_VERSION_TEXT_LENGTH];
685 
686     M_snprintf(name, sizeof(name), "%shex%d.hxs", SavePath, slot);
687 
688     fp = fopen(name, "rb");
689 
690     if (fp == NULL)
691     {
692         return false;
693     }
694 
695     found = fread(description, HXS_DESCRIPTION_LENGTH, 1, fp) == 1
696          && fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp) == 1;
697 
698     found = found && strcmp(versionText, HXS_VERSION_TEXT) == 0;
699 
700     fclose(fp);
701 
702     return found;
703 }
704 
705 //===========================================================================
706 //
707 // MN_LoadSlotText
708 //
709 // For each slot, looks for save games and reads the description field.
710 //
711 //===========================================================================
712 
MN_LoadSlotText(void)713 void MN_LoadSlotText(void)
714 {
715     char description[HXS_DESCRIPTION_LENGTH];
716     int slot;
717 
718     for (slot = 0; slot < 6; slot++)
719     {
720         if (ReadDescriptionForSlot(slot, description))
721         {
722             memcpy(SlotText[slot], description, SLOTTEXTLEN);
723             SlotStatus[slot] = 1;
724         }
725         else
726         {
727             memset(SlotText[slot], 0, SLOTTEXTLEN);
728             SlotStatus[slot] = 0;
729         }
730     }
731     slottextloaded = true;
732 }
733 
734 //---------------------------------------------------------------------------
735 //
736 // PROC DrawFileSlots
737 //
738 //---------------------------------------------------------------------------
739 
DrawFileSlots(Menu_t * menu)740 static void DrawFileSlots(Menu_t * menu)
741 {
742     int i;
743     int x;
744     int y;
745 
746     x = menu->x;
747     y = menu->y;
748     for (i = 0; i < 6; i++)
749     {
750         V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE));
751         if (SlotStatus[i])
752         {
753             MN_DrTextA(SlotText[i], x + 5, y + 5);
754         }
755         y += ITEM_HEIGHT;
756     }
757 }
758 
759 //---------------------------------------------------------------------------
760 //
761 // PROC DrawOptionsMenu
762 //
763 //---------------------------------------------------------------------------
764 
DrawOptionsMenu(void)765 static void DrawOptionsMenu(void)
766 {
767     if (messageson)
768     {
769         MN_DrTextB("ON", 196, 50);
770     }
771     else
772     {
773         MN_DrTextB("OFF", 196, 50);
774     }
775     DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity);
776 }
777 
778 //---------------------------------------------------------------------------
779 //
780 // PROC DrawOptions2Menu
781 //
782 //---------------------------------------------------------------------------
783 
DrawOptions2Menu(void)784 static void DrawOptions2Menu(void)
785 {
786     DrawSlider(&Options2Menu, 1, 9, screenblocks - 3);
787     DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
788     DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
789 }
790 
791 //---------------------------------------------------------------------------
792 //
793 // PROC SCQuitGame
794 //
795 //---------------------------------------------------------------------------
796 
SCQuitGame(int option)797 static void SCQuitGame(int option)
798 {
799     MenuActive = false;
800     askforquit = true;
801     typeofask = 1;              //quit game
802     if (!netgame && !demoplayback)
803     {
804         paused = true;
805     }
806 }
807 
808 //---------------------------------------------------------------------------
809 //
810 // PROC SCEndGame
811 //
812 //---------------------------------------------------------------------------
813 
SCEndGame(int option)814 static void SCEndGame(int option)
815 {
816     if (demoplayback)
817     {
818         return;
819     }
820     if (SCNetCheck(3))
821     {
822         MenuActive = false;
823         askforquit = true;
824         typeofask = 2;          //endgame
825         if (!netgame && !demoplayback)
826         {
827             paused = true;
828         }
829     }
830 }
831 
832 //---------------------------------------------------------------------------
833 //
834 // PROC SCMessages
835 //
836 //---------------------------------------------------------------------------
837 
SCMessages(int option)838 static void SCMessages(int option)
839 {
840     messageson ^= 1;
841     if (messageson)
842     {
843         P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
844     }
845     else
846     {
847         P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
848     }
849     S_StartSound(NULL, SFX_CHAT);
850 }
851 
852 //===========================================================================
853 //
854 // SCNetCheck
855 //
856 //===========================================================================
857 
SCNetCheck(int option)858 static boolean SCNetCheck(int option)
859 {
860     if (!netgame)
861     {
862         return true;
863     }
864     switch (option)
865     {
866         case 1:                // new game
867             P_SetMessage(&players[consoleplayer],
868                          "YOU CAN'T START A NEW GAME IN NETPLAY!", true);
869             break;
870         case 2:                // load game
871             P_SetMessage(&players[consoleplayer],
872                          "YOU CAN'T LOAD A GAME IN NETPLAY!", true);
873             break;
874         case 3:                // end game
875             P_SetMessage(&players[consoleplayer],
876                          "YOU CAN'T END A GAME IN NETPLAY!", true);
877             break;
878     }
879     MenuActive = false;
880     S_StartSound(NULL, SFX_CHAT);
881     return false;
882 }
883 
884 //===========================================================================
885 //
886 // SCNetCheck2
887 //
888 //===========================================================================
889 
SCNetCheck2(int option)890 static void SCNetCheck2(int option)
891 {
892     SCNetCheck(option);
893     return;
894 }
895 
896 //---------------------------------------------------------------------------
897 //
898 // PROC SCLoadGame
899 //
900 //---------------------------------------------------------------------------
901 
SCLoadGame(int option)902 static void SCLoadGame(int option)
903 {
904     if (demoplayback)
905     {
906         // deactivate playback, return control to player
907         demoextend = false;
908     }
909     if (!SlotStatus[option])
910     {                           // Don't try to load from an empty slot
911         return;
912     }
913     G_LoadGame(option);
914     MN_DeactivateMenu();
915     BorderNeedRefresh = true;
916     if (quickload == -1)
917     {
918         quickload = option + 1;
919         P_ClearMessage(&players[consoleplayer]);
920     }
921 }
922 
923 //---------------------------------------------------------------------------
924 //
925 // PROC SCSaveGame
926 //
927 //---------------------------------------------------------------------------
928 
SCSaveGame(int option)929 static void SCSaveGame(int option)
930 {
931     char *ptr;
932 
933     if (!FileMenuKeySteal)
934     {
935         int x, y;
936 
937         FileMenuKeySteal = true;
938         // We need to activate the text input interface to type the save
939         // game name:
940         x = SaveMenu.x + 1;
941         y = SaveMenu.y + 1 + option * ITEM_HEIGHT;
942         I_StartTextInput(x, y, x + 190, y + ITEM_HEIGHT - 2);
943 
944         M_StringCopy(oldSlotText, SlotText[option], sizeof(oldSlotText));
945         ptr = SlotText[option];
946         while (*ptr)
947         {
948             ptr++;
949         }
950         *ptr = '[';
951         *(ptr + 1) = 0;
952         SlotStatus[option]++;
953         currentSlot = option;
954         slotptr = ptr - SlotText[option];
955         return;
956     }
957     else
958     {
959         G_SaveGame(option, SlotText[option]);
960         FileMenuKeySteal = false;
961         I_StopTextInput();
962         MN_DeactivateMenu();
963     }
964     BorderNeedRefresh = true;
965     if (quicksave == -1)
966     {
967         quicksave = option + 1;
968         P_ClearMessage(&players[consoleplayer]);
969     }
970 }
971 
972 //==========================================================================
973 //
974 // SCClass
975 //
976 //==========================================================================
977 
SCClass(int option)978 static void SCClass(int option)
979 {
980     if (netgame)
981     {
982         P_SetMessage(&players[consoleplayer],
983                      "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!",
984                      true);
985         return;
986     }
987     MenuPClass = option;
988     switch (MenuPClass)
989     {
990         case PCLASS_FIGHTER:
991             SkillMenu.x = 120;
992             SkillItems[0].text = "SQUIRE";
993             SkillItems[1].text = "KNIGHT";
994             SkillItems[2].text = "WARRIOR";
995             SkillItems[3].text = "BERSERKER";
996             SkillItems[4].text = "TITAN";
997             break;
998         case PCLASS_CLERIC:
999             SkillMenu.x = 116;
1000             SkillItems[0].text = "ALTAR BOY";
1001             SkillItems[1].text = "ACOLYTE";
1002             SkillItems[2].text = "PRIEST";
1003             SkillItems[3].text = "CARDINAL";
1004             SkillItems[4].text = "POPE";
1005             break;
1006         case PCLASS_MAGE:
1007             SkillMenu.x = 112;
1008             SkillItems[0].text = "APPRENTICE";
1009             SkillItems[1].text = "ENCHANTER";
1010             SkillItems[2].text = "SORCERER";
1011             SkillItems[3].text = "WARLOCK";
1012             SkillItems[4].text = "ARCHIMAGE";
1013             break;
1014     }
1015     SetMenu(MENU_SKILL);
1016 }
1017 
1018 //---------------------------------------------------------------------------
1019 //
1020 // PROC SCSkill
1021 //
1022 //---------------------------------------------------------------------------
1023 
SCSkill(int option)1024 static void SCSkill(int option)
1025 {
1026     if (demoplayback)
1027     {
1028         // deactivate playback, return control to player
1029         demoextend = false;
1030     }
1031 
1032     PlayerClass[consoleplayer] = MenuPClass;
1033     G_DeferredNewGame(option);
1034     SB_SetClassData();
1035     SB_state = -1;
1036     MN_DeactivateMenu();
1037 }
1038 
1039 //---------------------------------------------------------------------------
1040 //
1041 // PROC SCMouseSensi
1042 //
1043 //---------------------------------------------------------------------------
1044 
SCMouseSensi(int option)1045 static void SCMouseSensi(int option)
1046 {
1047     if (option == RIGHT_DIR)
1048     {
1049         if (mouseSensitivity < 9)
1050         {
1051             mouseSensitivity++;
1052         }
1053     }
1054     else if (mouseSensitivity)
1055     {
1056         mouseSensitivity--;
1057     }
1058 }
1059 
1060 //---------------------------------------------------------------------------
1061 //
1062 // PROC SCSfxVolume
1063 //
1064 //---------------------------------------------------------------------------
1065 
SCSfxVolume(int option)1066 static void SCSfxVolume(int option)
1067 {
1068     if (option == RIGHT_DIR)
1069     {
1070         if (snd_MaxVolume < 15)
1071         {
1072             snd_MaxVolume++;
1073         }
1074     }
1075     else if (snd_MaxVolume)
1076     {
1077         snd_MaxVolume--;
1078     }
1079     soundchanged = true;        // we'll set it when we leave the menu
1080 }
1081 
1082 //---------------------------------------------------------------------------
1083 //
1084 // PROC SCMusicVolume
1085 //
1086 //---------------------------------------------------------------------------
1087 
SCMusicVolume(int option)1088 static void SCMusicVolume(int option)
1089 {
1090     if (option == RIGHT_DIR)
1091     {
1092         if (snd_MusicVolume < 15)
1093         {
1094             snd_MusicVolume++;
1095         }
1096     }
1097     else if (snd_MusicVolume)
1098     {
1099         snd_MusicVolume--;
1100     }
1101     S_SetMusicVolume();
1102 }
1103 
1104 //---------------------------------------------------------------------------
1105 //
1106 // PROC SCScreenSize
1107 //
1108 //---------------------------------------------------------------------------
1109 
SCScreenSize(int option)1110 static void SCScreenSize(int option)
1111 {
1112     if (option == RIGHT_DIR)
1113     {
1114         if (screenblocks < 11)
1115         {
1116             screenblocks++;
1117         }
1118     }
1119     else if (screenblocks > 3)
1120     {
1121         screenblocks--;
1122     }
1123     R_SetViewSize(screenblocks, detailLevel);
1124 }
1125 
1126 //---------------------------------------------------------------------------
1127 //
1128 // PROC SCInfo
1129 //
1130 //---------------------------------------------------------------------------
1131 
SCInfo(int option)1132 static void SCInfo(int option)
1133 {
1134     InfoType = 1;
1135     S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1136     if (!netgame && !demoplayback)
1137     {
1138         paused = true;
1139     }
1140 }
1141 
1142 //---------------------------------------------------------------------------
1143 //
1144 // FUNC MN_Responder
1145 //
1146 //---------------------------------------------------------------------------
1147 
MN_Responder(event_t * event)1148 boolean MN_Responder(event_t * event)
1149 {
1150     int key;
1151     int charTyped;
1152     int i;
1153     MenuItem_t *item;
1154     extern boolean automapactive;
1155     extern void H2_StartTitle(void);
1156     extern void G_CheckDemoStatus(void);
1157     char *textBuffer;
1158 
1159     // In testcontrols mode, none of the function keys should do anything
1160     // - the only key is escape to quit.
1161 
1162     if (testcontrols)
1163     {
1164         if (event->type == ev_quit
1165          || (event->type == ev_keydown
1166           && (event->data1 == key_menu_activate
1167            || event->data1 == key_menu_quit)))
1168         {
1169             I_Quit();
1170             return true;
1171         }
1172 
1173         return false;
1174     }
1175 
1176     // "close" button pressed on window?
1177     if (event->type == ev_quit)
1178     {
1179         // First click on close = bring up quit confirm message.
1180         // Second click = confirm quit.
1181 
1182         if (!MenuActive && askforquit && typeofask == 1)
1183         {
1184             G_CheckDemoStatus();
1185             I_Quit();
1186         }
1187         else
1188         {
1189             SCQuitGame(0);
1190             S_StartSound(NULL, SFX_CHAT);
1191         }
1192 
1193         return true;
1194     }
1195 
1196     // Allow the menu to be activated from a joystick button if a button
1197     // is bound for joybmenu.
1198     if (event->type == ev_joystick)
1199     {
1200         if (joybmenu >= 0 && (event->data1 & (1 << joybmenu)) != 0)
1201         {
1202             MN_ActivateMenu();
1203             return true;
1204         }
1205     }
1206 
1207     // Only care about keypresses beyond this point.
1208 
1209     if (event->type != ev_keydown)
1210     {
1211         return false;
1212     }
1213 
1214     key = event->data1;
1215     charTyped = event->data2;
1216 
1217     if (InfoType)
1218     {
1219         /* The 4-Level Demo Version also has 3 Info pages
1220         if (gamemode == shareware)
1221         {
1222             InfoType = (InfoType + 1) % 5;
1223         }
1224         else
1225         */
1226         {
1227             InfoType = (InfoType + 1) % 4;
1228         }
1229         if (key == KEY_ESCAPE)
1230         {
1231             InfoType = 0;
1232         }
1233         if (!InfoType)
1234         {
1235             if (!netgame && !demoplayback)
1236             {
1237                 paused = false;
1238             }
1239             MN_DeactivateMenu();
1240             SB_state = -1;      //refresh the statbar
1241             BorderNeedRefresh = true;
1242         }
1243         S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1244         return (true);          //make the info screen eat the keypress
1245     }
1246 
1247     if ((ravpic && key == KEY_F1) ||
1248         (key != 0 && key == key_menu_screenshot))
1249     {
1250         G_ScreenShot();
1251         return (true);
1252     }
1253 
1254     if (askforquit)
1255     {
1256         if (key == key_menu_confirm)
1257         {
1258             switch (typeofask)
1259             {
1260                 case 1:
1261                     G_CheckDemoStatus();
1262                     I_Quit();
1263                     return false;
1264                 case 2:
1265                     P_ClearMessage(&players[consoleplayer]);
1266                     askforquit = false;
1267                     typeofask = 0;
1268                     paused = false;
1269                     I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
1270                     H2_StartTitle();    // go to intro/demo mode.
1271                     return false;
1272                 case 3:
1273                     P_SetMessage(&players[consoleplayer],
1274                                  "QUICKSAVING....", false);
1275                     FileMenuKeySteal = true;
1276                     SCSaveGame(quicksave - 1);
1277                     BorderNeedRefresh = true;
1278                     break;
1279                 case 4:
1280                     P_SetMessage(&players[consoleplayer],
1281                                  "QUICKLOADING....", false);
1282                     SCLoadGame(quickload - 1);
1283                     BorderNeedRefresh = true;
1284                     break;
1285                 case 5:
1286                     BorderNeedRefresh = true;
1287                     mn_SuicideConsole = true;
1288                     break;
1289                 default:
1290                     break;
1291             }
1292 
1293             askforquit = false;
1294             typeofask = 0;
1295 
1296             return true;
1297         }
1298         else if (key == key_menu_abort || key == KEY_ESCAPE)
1299         {
1300             players[consoleplayer].messageTics = 0;
1301             askforquit = false;
1302             typeofask = 0;
1303             paused = false;
1304             UpdateState |= I_FULLSCRN;
1305             BorderNeedRefresh = true;
1306             return true;
1307         }
1308 
1309         return false;           // don't let the keys filter thru
1310     }
1311     if (!MenuActive && !chatmodeon)
1312     {
1313         if (key == key_menu_decscreen)
1314         {
1315             if (automapactive)
1316             {               // Don't screen size in automap
1317                 return (false);
1318             }
1319             SCScreenSize(LEFT_DIR);
1320             S_StartSound(NULL, SFX_PICKUP_KEY);
1321             BorderNeedRefresh = true;
1322             UpdateState |= I_FULLSCRN;
1323             return (true);
1324         }
1325         else if (key == key_menu_incscreen)
1326         {
1327             if (automapactive)
1328             {               // Don't screen size in automap
1329                 return (false);
1330             }
1331             SCScreenSize(RIGHT_DIR);
1332             S_StartSound(NULL, SFX_PICKUP_KEY);
1333             BorderNeedRefresh = true;
1334             UpdateState |= I_FULLSCRN;
1335             return (true);
1336         }
1337         else if (key == key_menu_help)           // F1 (help screen)
1338         {
1339             SCInfo(0);      // start up info screens
1340             MenuActive = true;
1341             return (true);
1342         }
1343         else if (key == key_menu_save)           // F2 (save game)
1344         {
1345             if (gamestate == GS_LEVEL && !demoplayback)
1346             {
1347                 MenuActive = true;
1348                 FileMenuKeySteal = false;
1349                 MenuTime = 0;
1350                 CurrentMenu = &SaveMenu;
1351                 CurrentItPos = CurrentMenu->oldItPos;
1352                 if (!netgame && !demoplayback)
1353                 {
1354                     paused = true;
1355                 }
1356                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1357                 slottextloaded = false;     //reload the slot text, when needed
1358             }
1359             return true;
1360         }
1361         else if (key == key_menu_load)           // F3 (load game)
1362         {
1363             if (SCNetCheck(2))
1364             {
1365                 MenuActive = true;
1366                 FileMenuKeySteal = false;
1367                 MenuTime = 0;
1368                 CurrentMenu = &LoadMenu;
1369                 CurrentItPos = CurrentMenu->oldItPos;
1370                 if (!netgame && !demoplayback)
1371                 {
1372                     paused = true;
1373                 }
1374                 S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1375                 slottextloaded = false;     //reload the slot text, when needed
1376             }
1377             return true;
1378         }
1379         else if (key == key_menu_volume)         // F4 (volume)
1380         {
1381             MenuActive = true;
1382             FileMenuKeySteal = false;
1383             MenuTime = 0;
1384             CurrentMenu = &Options2Menu;
1385             CurrentItPos = CurrentMenu->oldItPos;
1386             if (!netgame && !demoplayback)
1387             {
1388                 paused = true;
1389             }
1390             S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1391             slottextloaded = false; //reload the slot text, when needed
1392             return true;
1393         }
1394         else if (key == key_menu_detail)         // F5 (suicide)
1395         {
1396             MenuActive = false;
1397             askforquit = true;
1398             typeofask = 5;  // suicide
1399             return true;
1400         }
1401         else if (key == key_menu_qsave)          // F6 (quicksave)
1402         {
1403             if (gamestate == GS_LEVEL && !demoplayback)
1404             {
1405                 if (!quicksave || quicksave == -1)
1406                 {
1407                     MenuActive = true;
1408                     FileMenuKeySteal = false;
1409                     MenuTime = 0;
1410                     CurrentMenu = &SaveMenu;
1411                     CurrentItPos = CurrentMenu->oldItPos;
1412                     if (!netgame && !demoplayback)
1413                     {
1414                         paused = true;
1415                     }
1416                     S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1417                     slottextloaded = false; //reload the slot text
1418                     quicksave = -1;
1419                     P_SetMessage(&players[consoleplayer],
1420                                  "CHOOSE A QUICKSAVE SLOT", true);
1421                 }
1422                 else
1423                 {
1424                     askforquit = true;
1425                     typeofask = 3;
1426                     if (!netgame && !demoplayback)
1427                     {
1428                         paused = true;
1429                     }
1430                     S_StartSound(NULL, SFX_CHAT);
1431                 }
1432             }
1433             return true;
1434         }
1435         else if (key == key_menu_endgame)        // F7 (end game)
1436         {
1437             if (SCNetCheck(3))
1438             {
1439                 if (gamestate == GS_LEVEL && !demoplayback)
1440                 {
1441                     S_StartSound(NULL, SFX_CHAT);
1442                     SCEndGame(0);
1443                 }
1444             }
1445             return true;
1446         }
1447         else if (key == key_menu_messages)       // F8 (toggle messages)
1448         {
1449             SCMessages(0);
1450             return true;
1451         }
1452         else if (key == key_menu_qload)          // F9 (quickload)
1453         {
1454             if (SCNetCheck(2))
1455             {
1456                 if (!quickload || quickload == -1)
1457                 {
1458                     MenuActive = true;
1459                     FileMenuKeySteal = false;
1460                     MenuTime = 0;
1461                     CurrentMenu = &LoadMenu;
1462                     CurrentItPos = CurrentMenu->oldItPos;
1463                     if (!netgame && !demoplayback)
1464                     {
1465                         paused = true;
1466                     }
1467                     S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1468                     slottextloaded = false; // reload the slot text
1469                     quickload = -1;
1470                     P_SetMessage(&players[consoleplayer],
1471                                  "CHOOSE A QUICKLOAD SLOT", true);
1472                 }
1473                 else
1474                 {
1475                     askforquit = true;
1476                     if (!netgame && !demoplayback)
1477                     {
1478                         paused = true;
1479                     }
1480                     typeofask = 4;
1481                     S_StartSound(NULL, SFX_CHAT);
1482                 }
1483             }
1484             return true;
1485         }
1486         else if (key == key_menu_quit)           // F10 (quit)
1487         {
1488             if (gamestate == GS_LEVEL || gamestate == GS_FINALE)
1489             {
1490                 SCQuitGame(0);
1491                 S_StartSound(NULL, SFX_CHAT);
1492             }
1493             return true;
1494         }
1495         else if (key == key_menu_gamma)          // F11 (gamma correction)
1496         {
1497             usegamma++;
1498             if (usegamma > 4+4) // [crispy] intermediate gamma levels
1499             {
1500                 usegamma = 0;
1501             }
1502             SB_PaletteFlash(true);  // force change
1503             P_SetMessage(&players[consoleplayer], GammaText[usegamma],
1504                          false);
1505             return true;
1506         }
1507         else if (key == KEY_F12)                 // F12 (???)
1508         {
1509             // F12 - reload current map (devmaps mode)
1510 
1511             if (netgame)
1512             {
1513                 return false;
1514             }
1515             if (gamekeydown[key_speed])
1516             {               // Monsters ON
1517                 nomonsters = false;
1518             }
1519             if (gamekeydown[key_strafe])
1520             {               // Monsters OFF
1521                 nomonsters = true;
1522             }
1523             G_DeferedInitNew(gameskill, gameepisode, gamemap);
1524             P_SetMessage(&players[consoleplayer], TXT_CHEATWARP, false);
1525             return true;
1526         }
1527     }
1528 
1529     if (!MenuActive)
1530     {
1531         if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback)
1532         {
1533             MN_ActivateMenu();
1534             return (true);
1535         }
1536         return (false);
1537     }
1538     if (!FileMenuKeySteal)
1539     {
1540         item = &CurrentMenu->items[CurrentItPos];
1541 
1542         if (key == key_menu_down)                // Next menu item
1543         {
1544             do
1545             {
1546                 if (CurrentItPos + 1 > CurrentMenu->itemCount - 1)
1547                 {
1548                     CurrentItPos = 0;
1549                 }
1550                 else
1551                 {
1552                     CurrentItPos++;
1553                 }
1554             }
1555             while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
1556             S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
1557             return (true);
1558         }
1559         else if (key == key_menu_up)             // Previous menu item
1560         {
1561             do
1562             {
1563                 if (CurrentItPos == 0)
1564                 {
1565                     CurrentItPos = CurrentMenu->itemCount - 1;
1566                 }
1567                 else
1568                 {
1569                     CurrentItPos--;
1570                 }
1571             }
1572             while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
1573             S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
1574             return (true);
1575         }
1576         else if (key == key_menu_left)           // Slider left
1577         {
1578             if (item->type == ITT_LRFUNC && item->func != NULL)
1579             {
1580                 item->func(LEFT_DIR);
1581                 S_StartSound(NULL, SFX_PICKUP_KEY);
1582             }
1583             return (true);
1584         }
1585         else if (key == key_menu_right)          // Slider right
1586         {
1587             if (item->type == ITT_LRFUNC && item->func != NULL)
1588             {
1589                 item->func(RIGHT_DIR);
1590                 S_StartSound(NULL, SFX_PICKUP_KEY);
1591             }
1592             return (true);
1593         }
1594         else if (key == key_menu_forward)        // Activate item (enter)
1595         {
1596             if (item->type == ITT_SETMENU)
1597             {
1598                 if (item->func != NULL)
1599                 {
1600                     item->func(item->option);
1601                 }
1602                 SetMenu(item->menu);
1603             }
1604             else if (item->func != NULL)
1605             {
1606                 CurrentMenu->oldItPos = CurrentItPos;
1607                 if (item->type == ITT_LRFUNC)
1608                 {
1609                     item->func(RIGHT_DIR);
1610                 }
1611                 else if (item->type == ITT_EFUNC)
1612                 {
1613                     item->func(item->option);
1614                 }
1615             }
1616             S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
1617             return (true);
1618         }
1619         else if (key == key_menu_activate)
1620         {
1621             MN_DeactivateMenu();
1622             return (true);
1623         }
1624         else if (key == key_menu_back)
1625         {
1626             S_StartSound(NULL, SFX_PICKUP_KEY);
1627 
1628             if (CurrentMenu->prevMenu == MENU_NONE)
1629             {
1630                 MN_DeactivateMenu();
1631             }
1632             else
1633             {
1634                 SetMenu(CurrentMenu->prevMenu);
1635             }
1636             return (true);
1637         }
1638         else if (charTyped != 0)
1639         {
1640             for (i = 0; i < CurrentMenu->itemCount; i++)
1641             {
1642                 if (CurrentMenu->items[i].text)
1643                 {
1644                     if (toupper(charTyped)
1645                         == toupper(CurrentMenu->items[i].text[0]))
1646                     {
1647                         CurrentItPos = i;
1648                         return (true);
1649                     }
1650                 }
1651             }
1652         }
1653         return (false);
1654     }
1655     else
1656     {
1657         // Editing file names
1658         // When typing a savegame name, we use the fully shifted and
1659         // translated input value from event->data3.
1660         charTyped = event->data3;
1661         textBuffer = &SlotText[currentSlot][slotptr];
1662         if (key == KEY_BACKSPACE)
1663         {
1664             if (slotptr)
1665             {
1666                 *textBuffer = 0;
1667                 slotptr--;
1668                 textBuffer = &SlotText[currentSlot][slotptr];
1669                 *textBuffer = ASCII_CURSOR;
1670             }
1671             return (true);
1672         }
1673         if (key == KEY_ESCAPE)
1674         {
1675             M_StringCopy(SlotText[currentSlot], oldSlotText,
1676                          sizeof(SlotText[currentSlot]));
1677             SlotStatus[currentSlot]--;
1678             MN_DeactivateMenu();
1679             return (true);
1680         }
1681         if (key == KEY_ENTER)
1682         {
1683             SlotText[currentSlot][slotptr] = 0; // clear the cursor
1684             item = &CurrentMenu->items[CurrentItPos];
1685             CurrentMenu->oldItPos = CurrentItPos;
1686             if (item->type == ITT_EFUNC)
1687             {
1688                 item->func(item->option);
1689                 if (item->menu != MENU_NONE)
1690                 {
1691                     SetMenu(item->menu);
1692                 }
1693             }
1694             return (true);
1695         }
1696         if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
1697         {
1698             if (isalpha(charTyped))
1699             {
1700                 *textBuffer++ = toupper(charTyped);
1701                 *textBuffer = ASCII_CURSOR;
1702                 slotptr++;
1703                 return (true);
1704             }
1705             if (isdigit(charTyped) || charTyped == ' '
1706              || charTyped == ',' || charTyped == '.' || charTyped == '-'
1707              || charTyped == '!')
1708             {
1709                 *textBuffer++ = charTyped;
1710                 *textBuffer = ASCII_CURSOR;
1711                 slotptr++;
1712                 return (true);
1713             }
1714         }
1715         return (true);
1716     }
1717     return (false);
1718 }
1719 
1720 //---------------------------------------------------------------------------
1721 //
1722 // PROC MN_ActivateMenu
1723 //
1724 //---------------------------------------------------------------------------
1725 
MN_ActivateMenu(void)1726 void MN_ActivateMenu(void)
1727 {
1728     if (MenuActive)
1729     {
1730         return;
1731     }
1732     if (paused)
1733     {
1734         S_ResumeSound();
1735     }
1736     MenuActive = true;
1737     FileMenuKeySteal = false;
1738     MenuTime = 0;
1739     CurrentMenu = &MainMenu;
1740     CurrentItPos = CurrentMenu->oldItPos;
1741     if (!netgame && !demoplayback)
1742     {
1743         paused = true;
1744     }
1745     S_StartSound(NULL, SFX_PLATFORM_STOP);
1746     slottextloaded = false;     //reload the slot text, when needed
1747 }
1748 
1749 //---------------------------------------------------------------------------
1750 //
1751 // PROC MN_DeactivateMenu
1752 //
1753 //---------------------------------------------------------------------------
1754 
MN_DeactivateMenu(void)1755 void MN_DeactivateMenu(void)
1756 {
1757     if (CurrentMenu != NULL)
1758     {
1759         CurrentMenu->oldItPos = CurrentItPos;
1760     }
1761     MenuActive = false;
1762     if (FileMenuKeySteal)
1763     {
1764         I_StopTextInput();
1765     }
1766     if (!netgame)
1767     {
1768         paused = false;
1769     }
1770     S_StartSound(NULL, SFX_PLATFORM_STOP);
1771     P_ClearMessage(&players[consoleplayer]);
1772 }
1773 
1774 //---------------------------------------------------------------------------
1775 //
1776 // PROC MN_DrawInfo
1777 //
1778 //---------------------------------------------------------------------------
1779 
MN_DrawInfo(void)1780 void MN_DrawInfo(void)
1781 {
1782     I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
1783     V_CopyScaledBuffer(I_VideoBuffer,
1784            (byte *) W_CacheLumpNum(W_GetNumForName("TITLE") + InfoType,
1785                                    PU_CACHE), ORIGWIDTH * ORIGHEIGHT);
1786 //      V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType,
1787 //              PU_CACHE));
1788 }
1789 
1790 
1791 //---------------------------------------------------------------------------
1792 //
1793 // PROC SetMenu
1794 //
1795 //---------------------------------------------------------------------------
1796 
SetMenu(MenuType_t menu)1797 static void SetMenu(MenuType_t menu)
1798 {
1799     CurrentMenu->oldItPos = CurrentItPos;
1800     CurrentMenu = Menus[menu];
1801     CurrentItPos = CurrentMenu->oldItPos;
1802 }
1803 
1804 //---------------------------------------------------------------------------
1805 //
1806 // PROC DrawSlider
1807 //
1808 //---------------------------------------------------------------------------
1809 
DrawSlider(Menu_t * menu,int item,int width,int slot)1810 static void DrawSlider(Menu_t * menu, int item, int width, int slot)
1811 {
1812     int x;
1813     int y;
1814     int x2;
1815     int count;
1816 
1817     x = menu->x + 24;
1818     y = menu->y + 2 + (item * ITEM_HEIGHT);
1819     V_DrawPatch(x - 32, y, W_CacheLumpName("M_SLDLT", PU_CACHE));
1820     for (x2 = x, count = width; count--; x2 += 8)
1821     {
1822         V_DrawPatch(x2, y, W_CacheLumpName(count & 1 ? "M_SLDMD1"
1823                                            : "M_SLDMD2", PU_CACHE));
1824     }
1825     V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE));
1826     V_DrawPatch(x + 4 + slot * 8, y + 7,
1827                 W_CacheLumpName("M_SLDKB", PU_CACHE));
1828 }
1829