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