aboutsummaryrefslogtreecommitdiff
path: root/src/m_menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/m_menu.c')
-rw-r--r--src/m_menu.c5559
1 files changed, 5559 insertions, 0 deletions
diff --git a/src/m_menu.c b/src/m_menu.c
new file mode 100644
index 0000000..16afd60
--- /dev/null
+++ b/src/m_menu.c
@@ -0,0 +1,5559 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * DOOM selection menu, options, episode etc. (aka Big Font menus)
31 * Sliders and icons. Kinda widget stuff.
32 * Setup Menus.
33 * Extended HELP screens.
34 * Dynamic HELP screen.
35 *
36 *-----------------------------------------------------------------------------*/
37
38#include <stdio.h>
39#include <fcntl.h>
40
41#include "doomdef.h"
42#include "doomstat.h"
43#include "dstrings.h"
44#include "d_main.h"
45#include "v_video.h"
46#include "w_wad.h"
47#include "r_main.h"
48#include "hu_stuff.h"
49#include "g_game.h"
50#include "s_sound.h"
51#include "sounds.h"
52#include "m_menu.h"
53#include "d_deh.h"
54#include "m_misc.h"
55#include "lprintf.h"
56#include "am_map.h"
57#include "i_main.h"
58#include "i_system.h"
59#include "i_video.h"
60#include "i_sound.h"
61#include "r_demo.h"
62#include "r_fps.h"
63
64extern patchnum_t hu_font[HU_FONTSIZE];
65extern boolean message_dontfuckwithme;
66
67extern boolean chat_on; // in heads-up code
68
69//
70// defaulted values
71//
72
73int mouseSensitivity_horiz; // has default // killough
74int mouseSensitivity_vert; // has default
75
76int showMessages; // Show messages has default, 0 = off, 1 = on
77
78int hide_setup=1; // killough 5/15/98
79
80// Blocky mode, has default, 0 = high, 1 = normal
81//int detailLevel; obsolete -- killough
82int screenblocks; // has default
83
84int screenSize; // temp for screenblocks (0-9)
85
86int quickSaveSlot; // -1 = no quicksave slot picked!
87
88int messageToPrint; // 1 = message to be printed
89
90// CPhipps - static const
91static const char* messageString; // ...and here is the message string!
92
93// message x & y
94int messx;
95int messy;
96int messageLastMenuActive;
97
98boolean messageNeedsInput; // timed message = no input from user
99
100void (*messageRoutine)(int response);
101
102#define SAVESTRINGSIZE 24
103
104/* killough 8/15/98: when changes are allowed to sync-critical variables */
105static int allow_changes(void)
106{
107 return !(demoplayback || demorecording || netgame);
108}
109
110static void M_UpdateCurrent(default_t* def)
111{
112 /* cph - requires rewrite of m_misc.c */
113 if (def->current) {
114 if (allow_changes()) /* killough 8/15/98 */
115 *def->current = *def->location.pi;
116 else if (*def->current != *def->location.pi)
117 warn_about_changes(S_LEVWARN); /* killough 8/15/98 */
118 }
119}
120
121int warning_about_changes, print_warning_about_changes;
122
123/* cphipps - M_DrawBackground renamed and moved to v_video.c */
124#define M_DrawBackground V_DrawBackground
125
126// we are going to be entering a savegame string
127
128int saveStringEnter;
129int saveSlot; // which slot to save in
130int saveCharIndex; // which char we're editing
131// old save description before edit
132char saveOldString[SAVESTRINGSIZE];
133
134boolean inhelpscreens; // indicates we are in or just left a help screen
135
136boolean menuactive; // The menus are up
137
138#define SKULLXOFF -32
139#define LINEHEIGHT 16
140
141char savegamestrings[10][SAVESTRINGSIZE];
142
143//
144// MENU TYPEDEFS
145//
146
147typedef struct
148{
149 short status; // 0 = no cursor here, 1 = ok, 2 = arrows ok
150 char name[10];
151
152 // choice = menu item #.
153 // if status = 2,
154 // choice=0:leftarrow,1:rightarrow
155 void (*routine)(int choice);
156 char alphaKey; // hotkey in menu
157} menuitem_t;
158
159typedef struct menu_s
160{
161 short numitems; // # of menu items
162 struct menu_s* prevMenu; // previous menu
163 menuitem_t* menuitems; // menu items
164 void (*routine)(); // draw routine
165 short x;
166 short y; // x,y of menu
167 short lastOn; // last item user was on in menu
168} menu_t;
169
170short itemOn; // menu item skull is on (for Big Font menus)
171short skullAnimCounter; // skull animation counter
172short whichSkull; // which skull to draw (he blinks)
173
174// graphic name of skulls
175
176const char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
177
178menu_t* currentMenu; // current menudef
179
180// phares 3/30/98
181// externs added for setup menus
182
183extern int mousebfire;
184extern int mousebstrafe;
185extern int mousebforward;
186// proff 08/17/98: Added backward to mousebuttons
187extern int mousebbackward;
188extern int joybfire;
189extern int joybstrafe;
190extern int joybuse;
191extern int joybspeed;
192int mapcolor_me; // cph
193
194extern int map_point_coordinates; // killough 10/98
195
196extern char* chat_macros[]; // chat macros
197extern const char* shiftxform;
198extern default_t defaults[];
199extern int numdefaults;
200
201// end of externs added for setup menus
202
203//
204// PROTOTYPES
205//
206void M_NewGame(int choice);
207void M_Episode(int choice);
208void M_ChooseSkill(int choice);
209void M_LoadGame(int choice);
210void M_SaveGame(int choice);
211void M_Options(int choice);
212void M_EndGame(int choice);
213void M_ReadThis(int choice);
214void M_ReadThis2(int choice);
215void M_QuitDOOM(int choice);
216
217void M_ChangeMessages(int choice);
218void M_ChangeSensitivity(int choice);
219void M_SfxVol(int choice);
220void M_MusicVol(int choice);
221/* void M_ChangeDetail(int choice); unused -- killough */
222void M_SizeDisplay(int choice);
223void M_StartGame(int choice);
224void M_Sound(int choice);
225
226void M_Mouse(int choice, int *sens); /* killough */
227void M_MouseVert(int choice);
228void M_MouseHoriz(int choice);
229void M_DrawMouse(void);
230
231void M_FinishReadThis(int choice);
232void M_FinishHelp(int choice); // killough 10/98
233void M_LoadSelect(int choice);
234void M_SaveSelect(int choice);
235void M_ReadSaveStrings(void);
236void M_QuickSave(void);
237void M_QuickLoad(void);
238
239void M_DrawMainMenu(void);
240void M_DrawReadThis1(void);
241void M_DrawReadThis2(void);
242void M_DrawNewGame(void);
243void M_DrawEpisode(void);
244void M_DrawOptions(void);
245void M_DrawSound(void);
246void M_DrawLoad(void);
247void M_DrawSave(void);
248void M_DrawSetup(void); // phares 3/21/98
249void M_DrawHelp (void); // phares 5/04/98
250
251void M_DrawSaveLoadBorder(int x,int y);
252void M_SetupNextMenu(menu_t *menudef);
253void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
254void M_DrawEmptyCell(menu_t *menu,int item);
255void M_DrawSelCell(menu_t *menu,int item);
256void M_WriteText(int x, int y, const char *string);
257int M_StringWidth(const char *string);
258int M_StringHeight(const char *string);
259void M_StartMessage(const char *string,void *routine,boolean input);
260void M_StopMessage(void);
261void M_ClearMenus (void);
262
263// phares 3/30/98
264// prototypes added to support Setup Menus and Extended HELP screens
265
266int M_GetKeyString(int,int);
267void M_Setup(int choice);
268void M_KeyBindings(int choice);
269void M_Weapons(int);
270void M_StatusBar(int);
271void M_Automap(int);
272void M_Enemy(int);
273void M_Messages(int);
274void M_ChatStrings(int);
275void M_InitExtendedHelp(void);
276void M_ExtHelpNextScreen(int);
277void M_ExtHelp(int);
278static int M_GetPixelWidth(const char*);
279void M_DrawKeybnd(void);
280void M_DrawWeapons(void);
281static void M_DrawMenuString(int,int,int);
282static void M_DrawStringCentered(int,int,int,const char*);
283void M_DrawStatusHUD(void);
284void M_DrawExtHelp(void);
285void M_DrawAutoMap(void);
286void M_DrawEnemy(void);
287void M_DrawMessages(void);
288void M_DrawChatStrings(void);
289void M_Compat(int); // killough 10/98
290void M_ChangeDemoSmoothTurns(void);
291void M_General(int); // killough 10/98
292void M_DrawCompat(void); // killough 10/98
293void M_DrawGeneral(void); // killough 10/98
294void M_FullScreen(void); // nathanh 01/01
295
296menu_t NewDef; // phares 5/04/98
297
298// end of prototypes added to support Setup Menus and Extended HELP screens
299
300/////////////////////////////////////////////////////////////////////////////
301//
302// DOOM MENUS
303//
304
305/////////////////////////////
306//
307// MAIN MENU
308//
309
310// main_e provides numerical values for which Big Font screen you're on
311
312enum
313{
314 newgame = 0,
315 loadgame,
316 savegame,
317 options,
318 readthis,
319 quitdoom,
320 main_end
321} main_e;
322
323//
324// MainMenu is the definition of what the main menu Screen should look
325// like. Each entry shows that the cursor can land on each item (1), the
326// built-in graphic lump (i.e. "M_NGAME") that should be displayed,
327// the program which takes over when an item is selected, and the hotkey
328// associated with the item.
329//
330
331menuitem_t MainMenu[]=
332{
333 {1,"M_NGAME", M_NewGame, 'n'},
334 {1,"M_OPTION",M_Options, 'o'},
335 {1,"M_LOADG", M_LoadGame,'l'},
336 {1,"M_SAVEG", M_SaveGame,'s'},
337 // Another hickup with Special edition.
338 {1,"M_RDTHIS",M_ReadThis,'r'},
339 {1,"M_QUITG", M_QuitDOOM,'q'}
340};
341
342menu_t MainDef =
343{
344 main_end, // number of menu items
345 NULL, // previous menu screen
346 MainMenu, // table that defines menu items
347 M_DrawMainMenu, // drawing routine
348 97,64, // initial cursor position
349 0 // last menu item the user was on
350};
351
352//
353// M_DrawMainMenu
354//
355
356void M_DrawMainMenu(void)
357{
358 // CPhipps - patch drawing updated
359 V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH);
360}
361
362/////////////////////////////
363//
364// Read This! MENU 1 & 2
365//
366
367// There are no menu items on the Read This! screens, so read_e just
368// provides a placeholder to maintain structure.
369
370enum
371{
372 rdthsempty1,
373 read1_end
374} read_e;
375
376enum
377{
378 rdthsempty2,
379 read2_end
380} read_e2;
381
382enum // killough 10/98
383{
384 helpempty,
385 help_end
386} help_e;
387
388
389// The definitions of the Read This! screens
390
391menuitem_t ReadMenu1[] =
392{
393 {1,"",M_ReadThis2,0}
394};
395
396menuitem_t ReadMenu2[]=
397{
398 {1,"",M_FinishReadThis,0}
399};
400
401menuitem_t HelpMenu[]= // killough 10/98
402{
403 {1,"",M_FinishHelp,0}
404};
405
406menu_t ReadDef1 =
407{
408 read1_end,
409 &MainDef,
410 ReadMenu1,
411 M_DrawReadThis1,
412 330,175,
413 //280,185, // killough 2/21/98: fix help screens
414 0
415};
416
417menu_t ReadDef2 =
418{
419 read2_end,
420 &ReadDef1,
421 ReadMenu2,
422 M_DrawReadThis2,
423 330,175,
424 0
425};
426
427menu_t HelpDef = // killough 10/98
428{
429 help_end,
430 &HelpDef,
431 HelpMenu,
432 M_DrawHelp,
433 330,175,
434 0
435};
436
437//
438// M_ReadThis
439//
440
441void M_ReadThis(int choice)
442{
443 M_SetupNextMenu(&ReadDef1);
444}
445
446void M_ReadThis2(int choice)
447{
448 M_SetupNextMenu(&ReadDef2);
449}
450
451void M_FinishReadThis(int choice)
452{
453 M_SetupNextMenu(&MainDef);
454}
455
456void M_FinishHelp(int choice) // killough 10/98
457{
458 M_SetupNextMenu(&MainDef);
459}
460
461//
462// Read This Menus
463// Had a "quick hack to fix romero bug"
464//
465// killough 10/98: updated with new screens
466
467void M_DrawReadThis1(void)
468{
469 inhelpscreens = true;
470 if (gamemode == shareware)
471 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
472 else
473 M_DrawCredits();
474}
475
476//
477// Read This Menus - optional second page.
478//
479// killough 10/98: updated with new screens
480
481void M_DrawReadThis2(void)
482{
483 inhelpscreens = true;
484 if (gamemode == shareware)
485 M_DrawCredits();
486 else
487 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
488}
489
490/////////////////////////////
491//
492// EPISODE SELECT
493//
494
495//
496// episodes_e provides numbers for the episode menu items. The default is
497// 4, to accomodate Ultimate Doom. If the user is running anything else,
498// this is accounted for in the code.
499//
500
501enum
502{
503 ep1,
504 ep2,
505 ep3,
506 ep4,
507 ep_end
508} episodes_e;
509
510// The definitions of the Episodes menu
511
512menuitem_t EpisodeMenu[]=
513{
514 {1,"M_EPI1", M_Episode,'k'},
515 {1,"M_EPI2", M_Episode,'t'},
516 {1,"M_EPI3", M_Episode,'i'},
517 {1,"M_EPI4", M_Episode,'t'}
518};
519
520menu_t EpiDef =
521{
522 ep_end, // # of menu items
523 &MainDef, // previous menu
524 EpisodeMenu, // menuitem_t ->
525 M_DrawEpisode, // drawing routine ->
526 48,63, // x,y
527 ep1 // lastOn
528};
529
530//
531// M_Episode
532//
533int epi;
534
535void M_DrawEpisode(void)
536{
537 // CPhipps - patch drawing updated
538 V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH);
539}
540
541void M_Episode(int choice)
542{
543 if ( (gamemode == shareware) && choice) {
544 M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized
545 M_SetupNextMenu(&ReadDef1);
546 return;
547 }
548
549 // Yet another hack...
550 if ( (gamemode == registered) && (choice > 2))
551 {
552 lprintf( LO_WARN,
553 "M_Episode: 4th episode requires UltimateDOOM\n");
554 choice = 0;
555 }
556
557 epi = choice;
558 M_SetupNextMenu(&NewDef);
559}
560
561/////////////////////////////
562//
563// NEW GAME
564//
565
566// numerical values for the New Game menu items
567
568enum
569{
570 killthings,
571 toorough,
572 hurtme,
573 violence,
574 nightmare,
575 newg_end
576} newgame_e;
577
578// The definitions of the New Game menu
579
580menuitem_t NewGameMenu[]=
581{
582 {1,"M_JKILL", M_ChooseSkill, 'i'},
583 {1,"M_ROUGH", M_ChooseSkill, 'h'},
584 {1,"M_HURT", M_ChooseSkill, 'h'},
585 {1,"M_ULTRA", M_ChooseSkill, 'u'},
586 {1,"M_NMARE", M_ChooseSkill, 'n'}
587};
588
589menu_t NewDef =
590{
591 newg_end, // # of menu items
592 &EpiDef, // previous menu
593 NewGameMenu, // menuitem_t ->
594 M_DrawNewGame, // drawing routine ->
595 48,63, // x,y
596 hurtme // lastOn
597};
598
599//
600// M_NewGame
601//
602
603void M_DrawNewGame(void)
604{
605 // CPhipps - patch drawing updated
606 V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH);
607 V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH);
608}
609
610/* cph - make `New Game' restart the level in a netgame */
611static void M_RestartLevelResponse(int ch)
612{
613 if (ch != 'y')
614 return;
615
616 if (demorecording)
617 exit(0);
618
619 currentMenu->lastOn = itemOn;
620 M_ClearMenus ();
621 G_RestartLevel ();
622}
623
624void M_NewGame(int choice)
625{
626 if (netgame && !demoplayback) {
627 if (compatibility_level < lxdoom_1_compatibility)
628 M_StartMessage(s_NEWGAME,NULL,false); // Ty 03/27/98 - externalized
629 else // CPhipps - query restarting the level
630 M_StartMessage(s_RESTARTLEVEL,M_RestartLevelResponse,true);
631 return;
632 }
633
634 if (demorecording) { /* killough 5/26/98: exclude during demo recordings */
635 M_StartMessage("you can't start a new game\n"
636 "while recording a demo!\n\n"PRESSKEY,
637 NULL, false); // killough 5/26/98: not externalized
638 return;
639 }
640
641 if ( gamemode == commercial )
642 M_SetupNextMenu(&NewDef);
643 else
644 M_SetupNextMenu(&EpiDef);
645}
646
647// CPhipps - static
648static void M_VerifyNightmare(int ch)
649{
650 if (ch != 'y')
651 return;
652
653 G_DeferedInitNew(nightmare,epi+1,1);
654 M_ClearMenus ();
655}
656
657void M_ChooseSkill(int choice)
658{
659 if (choice == nightmare)
660 { // Ty 03/27/98 - externalized
661 M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true);
662 return;
663 }
664
665 G_DeferedInitNew(choice,epi+1,1);
666 M_ClearMenus ();
667}
668
669/////////////////////////////
670//
671// LOAD GAME MENU
672//
673
674// numerical values for the Load Game slots
675
676enum
677{
678 load1,
679 load2,
680 load3,
681 load4,
682 load5,
683 load6,
684 load7, //jff 3/15/98 extend number of slots
685 load8,
686 load_end
687} load_e;
688
689// The definitions of the Load Game screen
690
691menuitem_t LoadMenue[]=
692{
693 {1,"", M_LoadSelect,'1'},
694 {1,"", M_LoadSelect,'2'},
695 {1,"", M_LoadSelect,'3'},
696 {1,"", M_LoadSelect,'4'},
697 {1,"", M_LoadSelect,'5'},
698 {1,"", M_LoadSelect,'6'},
699 {1,"", M_LoadSelect,'7'}, //jff 3/15/98 extend number of slots
700 {1,"", M_LoadSelect,'8'},
701};
702
703menu_t LoadDef =
704{
705 load_end,
706 &MainDef,
707 LoadMenue,
708 M_DrawLoad,
709 80,34, //jff 3/15/98 move menu up
710 0
711};
712
713#define LOADGRAPHIC_Y 8
714
715//
716// M_LoadGame & Cie.
717//
718
719void M_DrawLoad(void)
720{
721 int i;
722
723 //jff 3/15/98 use symbolic load position
724 // CPhipps - patch drawing updated
725 V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH);
726 for (i = 0 ; i < load_end ; i++) {
727 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
728 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
729 }
730}
731
732//
733// Draw border for the savegame description
734//
735
736void M_DrawSaveLoadBorder(int x,int y)
737{
738 int i;
739
740 V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH);
741
742 for (i = 0 ; i < 24 ; i++)
743 {
744 V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH);
745 x += 8;
746 }
747
748 V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH);
749}
750
751//
752// User wants to load this game
753//
754
755void M_LoadSelect(int choice)
756{
757 // CPhipps - Modified so savegame filename is worked out only internal
758 // to g_game.c, this only passes the slot.
759
760 G_LoadGame(choice, false); // killough 3/16/98, 5/15/98: add slot, cmd
761
762 M_ClearMenus ();
763}
764
765//
766// killough 5/15/98: add forced loadgames
767//
768
769static void M_VerifyForcedLoadGame(int ch)
770{
771 if (ch=='y')
772 G_ForcedLoadGame();
773 free((char*)messageString); // free the message strdup()'ed below
774 M_ClearMenus();
775}
776
777void M_ForcedLoadGame(const char *msg)
778{
779 M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above
780}
781
782//
783// Selected from DOOM menu
784//
785
786void M_LoadGame (int choice)
787{
788 /* killough 5/26/98: exclude during demo recordings
789 * cph - unless a new demo */
790 if (demorecording && (compatibility_level < prboom_2_compatibility))
791 {
792 M_StartMessage("you can't load a game\n"
793 "while recording an old demo!\n\n"PRESSKEY,
794 NULL, false); // killough 5/26/98: not externalized
795 return;
796 }
797
798 M_SetupNextMenu(&LoadDef);
799 M_ReadSaveStrings();
800}
801
802/////////////////////////////
803//
804// SAVE GAME MENU
805//
806
807// The definitions of the Save Game screen
808
809menuitem_t SaveMenu[]=
810{
811 {1,"", M_SaveSelect,'1'},
812 {1,"", M_SaveSelect,'2'},
813 {1,"", M_SaveSelect,'3'},
814 {1,"", M_SaveSelect,'4'},
815 {1,"", M_SaveSelect,'5'},
816 {1,"", M_SaveSelect,'6'},
817 {1,"", M_SaveSelect,'7'}, //jff 3/15/98 extend number of slots
818 {1,"", M_SaveSelect,'8'},
819};
820
821menu_t SaveDef =
822{
823 load_end, // same number of slots as the Load Game screen
824 &MainDef,
825 SaveMenu,
826 M_DrawSave,
827 80,34, //jff 3/15/98 move menu up
828 0
829};
830
831//
832// M_ReadSaveStrings
833// read the strings from the savegame files
834//
835void M_ReadSaveStrings(void)
836{
837 int i;
838
839 for (i = 0 ; i < load_end ; i++) {
840 char name[PATH_MAX+1]; // killough 3/22/98
841 FILE *fp; // killough 11/98: change to use stdio
842
843 /* killough 3/22/98
844 * cph - add not-demoplayback parameter */
845 G_SaveGameName(name,sizeof(name),i,false);
846 fp = fopen(name,"rb");
847 if (!fp) { // Ty 03/27/98 - externalized:
848 strcpy(&savegamestrings[i][0],s_EMPTYSTRING);
849 LoadMenue[i].status = 0;
850 continue;
851 }
852 fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp);
853 fclose(fp);
854 LoadMenue[i].status = 1;
855 }
856}
857
858//
859// M_SaveGame & Cie.
860//
861void M_DrawSave(void)
862{
863 int i;
864
865 //jff 3/15/98 use symbolic load position
866 // CPhipps - patch drawing updated
867 V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH);
868 for (i = 0 ; i < load_end ; i++)
869 {
870 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
871 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
872 }
873
874 if (saveStringEnter)
875 {
876 i = M_StringWidth(savegamestrings[saveSlot]);
877 M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
878 }
879}
880
881//
882// M_Responder calls this when user is finished
883//
884static void M_DoSave(int slot)
885{
886 G_SaveGame (slot,savegamestrings[slot]);
887 M_ClearMenus ();
888
889 // PICK QUICKSAVE SLOT YET?
890 if (quickSaveSlot == -2)
891 quickSaveSlot = slot;
892}
893
894//
895// User wants to save. Start string input for M_Responder
896//
897void M_SaveSelect(int choice)
898{
899 // we are going to be intercepting all chars
900 saveStringEnter = 1;
901
902 saveSlot = choice;
903 strcpy(saveOldString,savegamestrings[choice]);
904 if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) // Ty 03/27/98 - externalized
905 savegamestrings[choice][0] = 0;
906 saveCharIndex = strlen(savegamestrings[choice]);
907}
908
909//
910// Selected from DOOM menu
911//
912void M_SaveGame (int choice)
913{
914 // killough 10/6/98: allow savegames during single-player demo playback
915 if (!usergame && (!demoplayback || netgame))
916 {
917 M_StartMessage(s_SAVEDEAD,NULL,false); // Ty 03/27/98 - externalized
918 return;
919 }
920
921 if (gamestate != GS_LEVEL)
922 return;
923
924 M_SetupNextMenu(&SaveDef);
925 M_ReadSaveStrings();
926}
927
928/////////////////////////////
929//
930// OPTIONS MENU
931//
932
933// numerical values for the Options menu items
934
935enum
936{
937 general, // killough 10/98
938 // killough 4/6/98: move setup to be a sub-menu of OPTIONs
939 setup, // phares 3/21/98
940 endgame,
941 messages,
942 /* detail, obsolete -- killough */
943 scrnsize,
944 option_empty1,
945 mousesens,
946 /* option_empty2, submenu now -- killough */
947 soundvol,
948 opt_end
949} options_e;
950
951// The definitions of the Options menu
952
953menuitem_t OptionsMenu[]=
954{
955 // killough 4/6/98: move setup to be a sub-menu of OPTIONs
956 {1,"M_GENERL", M_General, 'g'}, // killough 10/98
957 {1,"M_SETUP", M_Setup, 's'}, // phares 3/21/98
958 {1,"M_ENDGAM", M_EndGame,'e'},
959 {1,"M_MESSG", M_ChangeMessages,'m'},
960 /* {1,"M_DETAIL", M_ChangeDetail,'g'}, unused -- killough */
961 {2,"M_SCRNSZ", M_SizeDisplay,'s'},
962 {-1,"",0},
963 {1,"M_MSENS", M_ChangeSensitivity,'m'},
964 /* {-1,"",0}, replaced with submenu -- killough */
965 {1,"M_SVOL", M_Sound,'s'}
966};
967
968menu_t OptionsDef =
969{
970 opt_end,
971 &MainDef,
972 OptionsMenu,
973 M_DrawOptions,
974 60,37,
975 0
976};
977
978//
979// M_Options
980//
981char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
982char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
983
984
985void M_DrawOptions(void)
986{
987 // CPhipps - patch drawing updated
988 // proff/nicolas 09/20/98 -- changed for hi-res
989 V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH);
990
991 V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0,
992 msgNames[showMessages], CR_DEFAULT, VPT_STRETCH);
993
994 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
995 9,screenSize);
996}
997
998void M_Options(int choice)
999{
1000 M_SetupNextMenu(&OptionsDef);
1001}
1002
1003/////////////////////////////
1004//
1005// M_QuitDOOM
1006//
1007int quitsounds[8] =
1008{
1009 sfx_pldeth,
1010 sfx_dmpain,
1011 sfx_popain,
1012 sfx_slop,
1013 sfx_telept,
1014 sfx_posit1,
1015 sfx_posit3,
1016 sfx_sgtatk
1017};
1018
1019int quitsounds2[8] =
1020{
1021 sfx_vilact,
1022 sfx_getpow,
1023 sfx_boscub,
1024 sfx_slop,
1025 sfx_skeswg,
1026 sfx_kntdth,
1027 sfx_bspact,
1028 sfx_sgtatk
1029};
1030
1031static void M_QuitResponse(int ch)
1032{
1033 if (ch != 'y')
1034 return;
1035 if ((!netgame || demoplayback) // killough 12/98
1036 && !nosfxparm && snd_card) // avoid delay if no sound card
1037 {
1038 int i;
1039
1040 if (gamemode == commercial)
1041 S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
1042 else
1043 S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
1044
1045 // wait till all sounds stopped or 3 seconds are over
1046 i = 30;
1047 while (i>0) {
1048 I_uSleep(100000); // CPhipps - don't thrash cpu in this loop
1049 if (!I_AnySoundStillPlaying())
1050 break;
1051 i--;
1052 }
1053 }
1054 exit(0); // killough
1055}
1056
1057void M_QuitDOOM(int choice)
1058{
1059 static char endstring[160];
1060
1061 // We pick index 0 which is language sensitive,
1062 // or one at random, between 1 and maximum number.
1063 // Ty 03/27/98 - externalized DOSY as a string s_DOSY that's in the sprintf
1064 if (language != english)
1065 sprintf(endstring,"%s\n\n%s",s_DOSY, endmsg[0] );
1066 else // killough 1/18/98: fix endgame message calculation:
1067 sprintf(endstring,"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY);
1068
1069 M_StartMessage(endstring,M_QuitResponse,true);
1070}
1071
1072/////////////////////////////
1073//
1074// SOUND VOLUME MENU
1075//
1076
1077// numerical values for the Sound Volume menu items
1078// The 'empty' slots are where the sliding scales appear.
1079
1080enum
1081{
1082 sfx_vol,
1083 sfx_empty1,
1084 music_vol,
1085 sfx_empty2,
1086 sound_end
1087} sound_e;
1088
1089// The definitions of the Sound Volume menu
1090
1091menuitem_t SoundMenu[]=
1092{
1093 {2,"M_SFXVOL",M_SfxVol,'s'},
1094 {-1,"",0},
1095 {2,"M_MUSVOL",M_MusicVol,'m'},
1096 {-1,"",0}
1097};
1098
1099menu_t SoundDef =
1100{
1101 sound_end,
1102 &OptionsDef,
1103 SoundMenu,
1104 M_DrawSound,
1105 80,64,
1106 0
1107};
1108
1109//
1110// Change Sfx & Music volumes
1111//
1112
1113void M_DrawSound(void)
1114{
1115 // CPhipps - patch drawing updated
1116 V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH);
1117
1118 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),16,snd_SfxVolume);
1119
1120 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),16,snd_MusicVolume);
1121}
1122
1123void M_Sound(int choice)
1124{
1125 M_SetupNextMenu(&SoundDef);
1126}
1127
1128void M_SfxVol(int choice)
1129{
1130 switch(choice)
1131 {
1132 case 0:
1133 if (snd_SfxVolume)
1134 snd_SfxVolume--;
1135 break;
1136 case 1:
1137 if (snd_SfxVolume < 15)
1138 snd_SfxVolume++;
1139 break;
1140 }
1141
1142 S_SetSfxVolume(snd_SfxVolume /* *8 */);
1143}
1144
1145void M_MusicVol(int choice)
1146{
1147 switch(choice)
1148 {
1149 case 0:
1150 if (snd_MusicVolume)
1151 snd_MusicVolume--;
1152 break;
1153 case 1:
1154 if (snd_MusicVolume < 15)
1155 snd_MusicVolume++;
1156 break;
1157 }
1158
1159 S_SetMusicVolume(snd_MusicVolume /* *8 */);
1160}
1161
1162/////////////////////////////
1163//
1164// MOUSE SENSITIVITY MENU -- killough
1165//
1166
1167// numerical values for the Mouse Sensitivity menu items
1168// The 'empty' slots are where the sliding scales appear.
1169
1170enum
1171{
1172 mouse_horiz,
1173 mouse_empty1,
1174 mouse_vert,
1175 mouse_empty2,
1176 mouse_end
1177} mouse_e;
1178
1179// The definitions of the Mouse Sensitivity menu
1180
1181menuitem_t MouseMenu[]=
1182{
1183 {2,"M_HORSEN",M_MouseHoriz,'h'},
1184 {-1,"",0},
1185 {2,"M_VERSEN",M_MouseVert,'v'},
1186 {-1,"",0}
1187};
1188
1189menu_t MouseDef =
1190{
1191 mouse_end,
1192 &OptionsDef,
1193 MouseMenu,
1194 M_DrawMouse,
1195 60,64,
1196 0
1197};
1198
1199
1200// I'm using a scale of 100 since I don't know what's normal -- killough.
1201
1202#define MOUSE_SENS_MAX 100
1203
1204//
1205// Change Mouse Sensitivities -- killough
1206//
1207
1208void M_DrawMouse(void)
1209{
1210 int mhmx,mvmx; /* jff 4/3/98 clamp drawn position 99max mead */
1211
1212 // CPhipps - patch drawing updated
1213 V_DrawNamePatch(60, 38, 0, "M_MSENS", CR_DEFAULT, VPT_STRETCH);
1214
1215 //jff 4/3/98 clamp horizontal sensitivity display
1216 mhmx = mouseSensitivity_horiz>99? 99 : mouseSensitivity_horiz; /*mead*/
1217 M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_horiz+1),100,mhmx);
1218 //jff 4/3/98 clamp vertical sensitivity display
1219 mvmx = mouseSensitivity_vert>99? 99 : mouseSensitivity_vert; /*mead*/
1220 M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_vert+1),100,mvmx);
1221}
1222
1223void M_ChangeSensitivity(int choice)
1224{
1225 M_SetupNextMenu(&MouseDef); // killough
1226
1227 // switch(choice)
1228 // {
1229 // case 0:
1230 // if (mouseSensitivity)
1231 // mouseSensitivity--;
1232 // break;
1233 // case 1:
1234 // if (mouseSensitivity < 9)
1235 // mouseSensitivity++;
1236 // break;
1237 // }
1238}
1239
1240void M_MouseHoriz(int choice)
1241{
1242 M_Mouse(choice, &mouseSensitivity_horiz);
1243}
1244
1245void M_MouseVert(int choice)
1246{
1247 M_Mouse(choice, &mouseSensitivity_vert);
1248}
1249
1250void M_Mouse(int choice, int *sens)
1251{
1252 switch(choice)
1253 {
1254 case 0:
1255 if (*sens)
1256 --*sens;
1257 break;
1258 case 1:
1259 if (*sens < 99)
1260 ++*sens; /*mead*/
1261 break;
1262 }
1263}
1264
1265/////////////////////////////
1266//
1267// M_QuickSave
1268//
1269
1270char tempstring[80];
1271
1272static void M_QuickSaveResponse(int ch)
1273{
1274 if (ch == 'y') {
1275 M_DoSave(quickSaveSlot);
1276 S_StartSound(NULL,sfx_swtchx);
1277 }
1278}
1279
1280void M_QuickSave(void)
1281{
1282 if (!usergame && (!demoplayback || netgame)) { /* killough 10/98 */
1283 S_StartSound(NULL,sfx_oof);
1284 return;
1285 }
1286
1287 if (gamestate != GS_LEVEL)
1288 return;
1289
1290 if (quickSaveSlot < 0) {
1291 M_StartControlPanel();
1292 M_ReadSaveStrings();
1293 M_SetupNextMenu(&SaveDef);
1294 quickSaveSlot = -2; // means to pick a slot now
1295 return;
1296 }
1297 sprintf(tempstring,s_QSPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
1298 M_StartMessage(tempstring,M_QuickSaveResponse,true);
1299}
1300
1301/////////////////////////////
1302//
1303// M_QuickLoad
1304//
1305
1306static void M_QuickLoadResponse(int ch)
1307{
1308 if (ch == 'y') {
1309 M_LoadSelect(quickSaveSlot);
1310 S_StartSound(NULL,sfx_swtchx);
1311 }
1312}
1313
1314void M_QuickLoad(void)
1315{
1316 // cph - removed restriction against quickload in a netgame
1317
1318 if (demorecording) { // killough 5/26/98: exclude during demo recordings
1319 M_StartMessage("you can't quickload\n"
1320 "while recording a demo!\n\n"PRESSKEY,
1321 NULL, false); // killough 5/26/98: not externalized
1322 return;
1323 }
1324
1325 if (quickSaveSlot < 0) {
1326 M_StartMessage(s_QSAVESPOT,NULL,false); // Ty 03/27/98 - externalized
1327 return;
1328 }
1329 sprintf(tempstring,s_QLPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
1330 M_StartMessage(tempstring,M_QuickLoadResponse,true);
1331}
1332
1333/////////////////////////////
1334//
1335// M_EndGame
1336//
1337
1338static void M_EndGameResponse(int ch)
1339{
1340 if (ch != 'y')
1341 return;
1342
1343 // killough 5/26/98: make endgame quit if recording or playing back demo
1344 if (demorecording || singledemo)
1345 G_CheckDemoStatus();
1346
1347 currentMenu->lastOn = itemOn;
1348 M_ClearMenus ();
1349 D_StartTitle ();
1350}
1351
1352void M_EndGame(int choice)
1353{
1354 if (netgame)
1355 {
1356 M_StartMessage(s_NETEND,NULL,false); // Ty 03/27/98 - externalized
1357 return;
1358 }
1359 M_StartMessage(s_ENDGAME,M_EndGameResponse,true); // Ty 03/27/98 - externalized
1360}
1361
1362/////////////////////////////
1363//
1364// Toggle messages on/off
1365//
1366
1367void M_ChangeMessages(int choice)
1368{
1369 // warning: unused parameter `int choice'
1370 choice = 0;
1371 showMessages = 1 - showMessages;
1372
1373 if (!showMessages)
1374 players[consoleplayer].message = s_MSGOFF; // Ty 03/27/98 - externalized
1375 else
1376 players[consoleplayer].message = s_MSGON ; // Ty 03/27/98 - externalized
1377
1378 message_dontfuckwithme = true;
1379}
1380
1381/////////////////////////////
1382//
1383// CHANGE DISPLAY SIZE
1384//
1385// jff 2/23/98 restored to pre-HUD state
1386// hud_active controlled soley by F5=key_detail (key_hud)
1387// hud_displayed is toggled by + or = in fullscreen
1388// hud_displayed is cleared by -
1389
1390void M_SizeDisplay(int choice)
1391{
1392 switch(choice) {
1393 case 0:
1394 if (screenSize > 0) {
1395 screenblocks--;
1396 screenSize--;
1397 hud_displayed = 0;
1398 }
1399 break;
1400 case 1:
1401 if (screenSize < 8) {
1402 screenblocks++;
1403 screenSize++;
1404 }
1405 else
1406 hud_displayed = !hud_displayed;
1407 break;
1408 }
1409 R_SetViewSize (screenblocks /*, detailLevel obsolete -- killough */);
1410}
1411
1412//
1413// End of Original Menus
1414//
1415/////////////////////////////////////////////////////////////////////////////
1416
1417/////////////////////////////////////////////////////////////////////////////
1418//
1419// SETUP MENU (phares)
1420//
1421// We've added a set of Setup Screens from which you can configure a number
1422// of variables w/o having to restart the game. There are 7 screens:
1423//
1424// Key Bindings
1425// Weapons
1426// Status Bar / HUD
1427// Automap
1428// Enemies
1429// Messages
1430// Chat Strings
1431//
1432// killough 10/98: added Compatibility and General menus
1433//
1434
1435/////////////////////////////
1436//
1437// booleans for setup screens
1438// these tell you what state the setup screens are in, and whether any of
1439// the overlay screens (automap colors, reset button message) should be
1440// displayed
1441
1442boolean setup_active = false; // in one of the setup screens
1443boolean set_keybnd_active = false; // in key binding setup screens
1444boolean set_weapon_active = false; // in weapons setup screen
1445boolean set_status_active = false; // in status bar/hud setup screen
1446boolean set_auto_active = false; // in automap setup screen
1447boolean set_enemy_active = false; // in enemies setup screen
1448boolean set_mess_active = false; // in messages setup screen
1449boolean set_chat_active = false; // in chat string setup screen
1450boolean setup_select = false; // changing an item
1451boolean setup_gather = false; // gathering keys for value
1452boolean colorbox_active = false; // color palette being shown
1453boolean default_verify = false; // verify reset defaults decision
1454boolean set_general_active = false;
1455boolean set_compat_active = false;
1456
1457/////////////////////////////
1458//
1459// set_menu_itemon is an index that starts at zero, and tells you which
1460// item on the current screen the cursor is sitting on.
1461//
1462// current_setup_menu is a pointer to the current setup menu table.
1463
1464static int set_menu_itemon; // which setup item is selected? // phares 3/98
1465setup_menu_t* current_setup_menu; // points to current setup menu table
1466
1467/////////////////////////////
1468//
1469// The menu_buffer is used to construct strings for display on the screen.
1470
1471static char menu_buffer[64];
1472
1473/////////////////////////////
1474//
1475// The setup_e enum is used to provide a unique number for each group of Setup
1476// Screens.
1477
1478enum
1479{
1480 set_compat,
1481 set_key_bindings,
1482 set_weapons,
1483 set_statbar,
1484 set_automap,
1485 set_enemy,
1486 set_messages,
1487 set_chatstrings,
1488 set_setup_end
1489} setup_e;
1490
1491int setup_screen; // the current setup screen. takes values from setup_e
1492
1493/////////////////////////////
1494//
1495// SetupMenu is the definition of what the main Setup Screen should look
1496// like. Each entry shows that the cursor can land on each item (1), the
1497// built-in graphic lump (i.e. "M_KEYBND") that should be displayed,
1498// the program which takes over when an item is selected, and the hotkey
1499// associated with the item.
1500
1501menuitem_t SetupMenu[]=
1502{
1503 {1,"M_COMPAT",M_Compat, 'p'},
1504 {1,"M_KEYBND",M_KeyBindings,'k'},
1505 {1,"M_WEAP" ,M_Weapons, 'w'},
1506 {1,"M_STAT" ,M_StatusBar, 's'},
1507 {1,"M_AUTO" ,M_Automap, 'a'},
1508 {1,"M_ENEM" ,M_Enemy, 'e'},
1509 {1,"M_MESS" ,M_Messages, 'm'},
1510 {1,"M_CHAT" ,M_ChatStrings,'c'},
1511};
1512
1513/////////////////////////////
1514//
1515// M_DoNothing does just that: nothing. Just a placeholder.
1516
1517static void M_DoNothing(int choice)
1518{
1519}
1520
1521/////////////////////////////
1522//
1523// Items needed to satisfy the 'Big Font' menu structures:
1524//
1525// the generic_setup_e enum mimics the 'Big Font' menu structures, but
1526// means nothing to the Setup Menus.
1527
1528enum
1529{
1530 generic_setupempty1,
1531 generic_setup_end
1532} generic_setup_e;
1533
1534// Generic_Setup is a do-nothing definition that the mainstream Menu code
1535// can understand, while the Setup Menu code is working. Another placeholder.
1536
1537menuitem_t Generic_Setup[] =
1538{
1539 {1,"",M_DoNothing,0}
1540};
1541
1542/////////////////////////////
1543//
1544// SetupDef is the menu definition that the mainstream Menu code understands.
1545// This is used by M_Setup (below) to define what is drawn and what is done
1546// with the main Setup screen.
1547
1548menu_t SetupDef =
1549{
1550 set_setup_end, // number of Setup Menu items (Key Bindings, etc.)
1551 &OptionsDef, // menu to return to when BACKSPACE is hit on this menu
1552 SetupMenu, // definition of items to show on the Setup Screen
1553 M_DrawSetup, // program that draws the Setup Screen
1554 59,37, // x,y position of the skull (modified when the skull is
1555 // drawn). The skull is parked on the upper-left corner
1556 // of the Setup screens, since it isn't needed as a cursor
1557 0 // last item the user was on for this menu
1558};
1559
1560/////////////////////////////
1561//
1562// Here are the definitions of the individual Setup Menu screens. They
1563// follow the format of the 'Big Font' menu structures. See the comments
1564// for SetupDef (above) to help understand what each of these says.
1565
1566menu_t KeybndDef =
1567{
1568 generic_setup_end,
1569 &SetupDef,
1570 Generic_Setup,
1571 M_DrawKeybnd,
1572 34,5, // skull drawn here
1573 0
1574};
1575
1576menu_t WeaponDef =
1577{
1578 generic_setup_end,
1579 &SetupDef,
1580 Generic_Setup,
1581 M_DrawWeapons,
1582 34,5, // skull drawn here
1583 0
1584};
1585
1586menu_t StatusHUDDef =
1587{
1588 generic_setup_end,
1589 &SetupDef,
1590 Generic_Setup,
1591 M_DrawStatusHUD,
1592 34,5, // skull drawn here
1593 0
1594};
1595
1596menu_t AutoMapDef =
1597{
1598 generic_setup_end,
1599 &SetupDef,
1600 Generic_Setup,
1601 M_DrawAutoMap,
1602 34,5, // skull drawn here
1603 0
1604};
1605
1606menu_t EnemyDef = // phares 4/08/98
1607{
1608 generic_setup_end,
1609 &SetupDef,
1610 Generic_Setup,
1611 M_DrawEnemy,
1612 34,5, // skull drawn here
1613 0
1614};
1615
1616menu_t MessageDef = // phares 4/08/98
1617{
1618 generic_setup_end,
1619 &SetupDef,
1620 Generic_Setup,
1621 M_DrawMessages,
1622 34,5, // skull drawn here
1623 0
1624};
1625
1626menu_t ChatStrDef = // phares 4/10/98
1627{
1628 generic_setup_end,
1629 &SetupDef,
1630 Generic_Setup,
1631 M_DrawChatStrings,
1632 34,5, // skull drawn here
1633 0
1634};
1635
1636menu_t GeneralDef = // killough 10/98
1637{
1638 generic_setup_end,
1639 &OptionsDef,
1640 Generic_Setup,
1641 M_DrawGeneral,
1642 34,5, // skull drawn here
1643 0
1644};
1645
1646menu_t CompatDef = // killough 10/98
1647{
1648 generic_setup_end,
1649 &SetupDef,
1650 Generic_Setup,
1651 M_DrawCompat,
1652 34,5, // skull drawn here
1653 0
1654};
1655
1656/////////////////////////////
1657//
1658// Draws the Title for the main Setup screen
1659
1660void M_DrawSetup(void)
1661{
1662 // CPhipps - patch drawing updated
1663 V_DrawNamePatch(124, 15, 0, "M_SETUP", CR_DEFAULT, VPT_STRETCH);
1664}
1665
1666/////////////////////////////
1667//
1668// Uses the SetupDef structure to draw the menu items for the main
1669// Setup screen
1670
1671void M_Setup(int choice)
1672{
1673 M_SetupNextMenu(&SetupDef);
1674}
1675
1676/////////////////////////////
1677//
1678// Data that's used by the Setup screen code
1679//
1680// Establish the message colors to be used
1681
1682#define CR_TITLE CR_GOLD
1683#define CR_SET CR_GREEN
1684#define CR_ITEM CR_RED
1685#define CR_HILITE CR_ORANGE
1686#define CR_SELECT CR_GRAY
1687
1688// Data used by the Automap color selection code
1689
1690#define CHIP_SIZE 7 // size of color block for colored items
1691
1692#define COLORPALXORIG ((320 - 16*(CHIP_SIZE+1))/2)
1693#define COLORPALYORIG ((200 - 16*(CHIP_SIZE+1))/2)
1694
1695#define PAL_BLACK 0
1696#define PAL_WHITE 4
1697
1698// Data used by the Chat String editing code
1699
1700#define CHAT_STRING_BFR_SIZE 128
1701
1702// chat strings must fit in this screen space
1703// killough 10/98: reduced, for more general uses
1704#define MAXCHATWIDTH 272
1705
1706int chat_index;
1707char* chat_string_buffer; // points to new chat strings while editing
1708
1709/////////////////////////////
1710//
1711// phares 4/17/98:
1712// Added 'Reset to Defaults' Button to Setup Menu screens
1713// This is a small button that sits in the upper-right-hand corner of
1714// the first screen for each group. It blinks when selected, thus the
1715// two patches, which it toggles back and forth.
1716
1717char ResetButtonName[2][8] = {"M_BUTT1","M_BUTT2"};
1718
1719/////////////////////////////
1720//
1721// phares 4/18/98:
1722// Consolidate Item drawing code
1723//
1724// M_DrawItem draws the description of the provided item (the left-hand
1725// part). A different color is used for the text depending on whether the
1726// item is selected or not, or whether it's about to change.
1727
1728// CPhipps - static, hanging else removed, const parameter
1729static void M_DrawItem(const setup_menu_t* s)
1730{
1731 int x = s->m_x;
1732 int y = s->m_y;
1733 int flags = s->m_flags;
1734 if (flags & S_RESET)
1735
1736 // This item is the reset button
1737 // Draw the 'off' version if this isn't the current menu item
1738 // Draw the blinking version in tune with the blinking skull otherwise
1739
1740 // proff/nicolas 09/20/98 -- changed for hi-res
1741 // CPhipps - Patch drawing updated, reformatted
1742
1743 V_DrawNamePatch(x, y, 0, ResetButtonName[(flags & (S_HILITE|S_SELECT)) ? whichSkull : 0],
1744 CR_DEFAULT, VPT_STRETCH);
1745
1746 else { // Draw the item string
1747 char *p, *t;
1748 int w = 0;
1749 int color =
1750 flags & S_SELECT ? CR_SELECT :
1751 flags & S_HILITE ? CR_HILITE :
1752 flags & (S_TITLE|S_NEXT|S_PREV) ? CR_TITLE : CR_ITEM; // killough 10/98
1753
1754 /* killough 10/98:
1755 * Enhance to support multiline text separated by newlines.
1756 * This supports multiline items on horizontally-crowded menus.
1757 */
1758
1759 for (p = t = strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL)
1760 { /* killough 10/98: support left-justification: */
1761 strcpy(menu_buffer,p);
1762 if (!(flags & S_LEFTJUST))
1763 w = M_GetPixelWidth(menu_buffer) + 4;
1764 M_DrawMenuString(x - w, y ,color);
1765 }
1766 free(t);
1767 }
1768}
1769
1770// If a number item is being changed, allow up to N keystrokes to 'gather'
1771// the value. Gather_count tells you how many you have so far. The legality
1772// of what is gathered is determined by the low/high settings for the item.
1773
1774#define MAXGATHER 5
1775int gather_count;
1776char gather_buffer[MAXGATHER+1]; // killough 10/98: make input character-based
1777
1778/////////////////////////////
1779//
1780// phares 4/18/98:
1781// Consolidate Item Setting drawing code
1782//
1783// M_DrawSetting draws the setting of the provided item (the right-hand
1784// part. It determines the text color based on whether the item is
1785// selected or being changed. Then, depending on the type of item, it
1786// displays the appropriate setting value: yes/no, a key binding, a number,
1787// a paint chip, etc.
1788
1789static void M_DrawSetting(const setup_menu_t* s)
1790{
1791 int x = s->m_x, y = s->m_y, flags = s->m_flags, color;
1792
1793 // Determine color of the text. This may or may not be used later,
1794 // depending on whether the item is a text string or not.
1795
1796 color = flags & S_SELECT ? CR_SELECT : flags & S_HILITE ? CR_HILITE : CR_SET;
1797
1798 // Is the item a YES/NO item?
1799
1800 if (flags & S_YESNO) {
1801 strcpy(menu_buffer,*s->var.def->location.pi ? "YES" : "NO");
1802 M_DrawMenuString(x,y,color);
1803 return;
1804 }
1805
1806 // Is the item a simple number?
1807
1808 if (flags & S_NUM) {
1809 // killough 10/98: We must draw differently for items being gathered.
1810 if (flags & (S_HILITE|S_SELECT) && setup_gather) {
1811 gather_buffer[gather_count] = 0;
1812 strcpy(menu_buffer, gather_buffer);
1813 }
1814 else
1815 sprintf(menu_buffer,"%d",*s->var.def->location.pi);
1816 M_DrawMenuString(x,y,color);
1817 return;
1818 }
1819
1820 // Is the item a key binding?
1821
1822 if (flags & S_KEY) { // Key Binding
1823 int *key = s->var.m_key;
1824
1825 // Draw the key bound to the action
1826
1827 if (key) {
1828 M_GetKeyString(*key,0); // string to display
1829 if (key == &key_use) {
1830 // For the 'use' key, you have to build the string
1831
1832 if (s->m_mouse)
1833 sprintf(menu_buffer+strlen(menu_buffer), "/DBL-CLK MB%d",*s->m_mouse+1);
1834 if (s->m_joy)
1835 sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",*s->m_joy+1);
1836 }
1837 else if (key == &key_up || key == &key_speed ||
1838 key == &key_fire || key == &key_strafe)
1839 {
1840 if (s->m_mouse)
1841 sprintf(menu_buffer+strlen(menu_buffer), "/MB%d",
1842 *s->m_mouse+1);
1843 if (s->m_joy)
1844 sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",
1845 *s->m_joy+1);
1846 }
1847 M_DrawMenuString(x,y,color);
1848 }
1849 return;
1850 }
1851
1852 // Is the item a weapon number?
1853 // OR, Is the item a colored text string from the Automap?
1854 //
1855 // killough 10/98: removed special code, since the rest of the engine
1856 // already takes care of it, and this code prevented the user from setting
1857 // their overall weapons preferences while playing Doom 1.
1858 //
1859 // killough 11/98: consolidated weapons code with color range code
1860
1861 if (flags & (S_WEAP|S_CRITEM)) // weapon number or color range
1862 {
1863 sprintf(menu_buffer,"%d", *s->var.def->location.pi);
1864 M_DrawMenuString(x,y, flags & S_CRITEM ? *s->var.def->location.pi : color);
1865 return;
1866 }
1867
1868 // Is the item a paint chip?
1869
1870 if (flags & S_COLOR) // Automap paint chip
1871 {
1872 int ch;
1873
1874 ch = *s->var.def->location.pi;
1875 // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
1876 // draw the paint chip
1877 V_FillRect(0, x*SCREENWIDTH/320, (y-1)*SCREENHEIGHT/200,
1878 8*SCREENWIDTH/320, 8*SCREENHEIGHT/200,
1879 PAL_BLACK);
1880 V_FillRect(0, (x+1)*SCREENWIDTH/320, y*SCREENHEIGHT/200,
1881 6*SCREENWIDTH/320, 6*SCREENHEIGHT/200,
1882 (byte)ch);
1883
1884 if (!ch) // don't show this item in automap mode
1885 V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH);
1886 return;
1887 }
1888
1889 // Is the item a chat string?
1890 // killough 10/98: or a filename?
1891
1892 if (flags & S_STRING) {
1893 /* cph - cast to char* as it's really a Z_Strdup'd string (see m_misc.h) */
1894 char *text = (char*)*s->var.def->location.ppsz;
1895
1896 // Are we editing this string? If so, display a cursor under
1897 // the correct character.
1898
1899 if (setup_select && (s->m_flags & (S_HILITE|S_SELECT))) {
1900 int cursor_start, char_width;
1901 char c[2];
1902
1903 // If the string is too wide for the screen, trim it back,
1904 // one char at a time until it fits. This should only occur
1905 // while you're editing the string.
1906
1907 while (M_GetPixelWidth(text) >= MAXCHATWIDTH) {
1908 int len = strlen(text);
1909 text[--len] = 0;
1910 if (chat_index > len)
1911 chat_index--;
1912 }
1913
1914 // Find the distance from the beginning of the string to
1915 // where the cursor should be drawn, plus the width of
1916 // the char the cursor is under..
1917
1918 *c = text[chat_index]; // hold temporarily
1919 c[1] = 0;
1920 char_width = M_GetPixelWidth(c);
1921 if (char_width == 1)
1922 char_width = 7; // default for end of line
1923 text[chat_index] = 0; // NULL to get cursor position
1924 cursor_start = M_GetPixelWidth(text);
1925 text[chat_index] = *c; // replace stored char
1926
1927 // Now draw the cursor
1928 // proff 12/6/98: Drawing of cursor changed for hi-res
1929 V_FillRect(0, ((x+cursor_start-1)*SCREENWIDTH)/320, (y*SCREENHEIGHT)/200,
1930 (char_width*SCREENWIDTH)/320, 9*SCREENHEIGHT/200, PAL_WHITE);
1931 }
1932
1933 // Draw the setting for the item
1934
1935 strcpy(menu_buffer,text);
1936 M_DrawMenuString(x,y,color);
1937 return;
1938 }
1939
1940 // Is the item a selection of choices?
1941
1942 if (flags & S_CHOICE) {
1943 if (s->var.def->type == def_int) {
1944 if (s->selectstrings == NULL) {
1945 sprintf(menu_buffer,"%d",*s->var.def->location.pi);
1946 } else {
1947 strcpy(menu_buffer,s->selectstrings[*s->var.def->location.pi]);
1948 }
1949 }
1950
1951 if (s->var.def->type == def_str) {
1952 sprintf(menu_buffer,"%s", *s->var.def->location.ppsz);
1953 }
1954
1955 M_DrawMenuString(x,y,color);
1956 return;
1957 }
1958}
1959
1960/////////////////////////////
1961//
1962// M_DrawScreenItems takes the data for each menu item and gives it to
1963// the drawing routines above.
1964
1965// CPhipps - static, const parameter, formatting
1966static void M_DrawScreenItems(const setup_menu_t* src)
1967{
1968 if (print_warning_about_changes > 0) { /* killough 8/15/98: print warning */
1969 if (warning_about_changes & S_BADVAL) {
1970 strcpy(menu_buffer, "Value out of Range");
1971 M_DrawMenuString(100,176,CR_RED);
1972 } else if (warning_about_changes & S_PRGWARN) {
1973 strcpy(menu_buffer, "Warning: Program must be restarted to see changes");
1974 M_DrawMenuString(3, 176, CR_RED);
1975 } else if (warning_about_changes & S_BADVID) {
1976 strcpy(menu_buffer, "Video mode not supported");
1977 M_DrawMenuString(80,176,CR_RED);
1978 } else {
1979 strcpy(menu_buffer, "Warning: Changes are pending until next game");
1980 M_DrawMenuString(18,184,CR_RED);
1981 }
1982 }
1983
1984 while (!(src->m_flags & S_END)) {
1985
1986 // See if we're to draw the item description (left-hand part)
1987
1988 if (src->m_flags & S_SHOWDESC)
1989 M_DrawItem(src);
1990
1991 // See if we're to draw the setting (right-hand part)
1992
1993 if (src->m_flags & S_SHOWSET)
1994 M_DrawSetting(src);
1995 src++;
1996 }
1997}
1998
1999/////////////////////////////
2000//
2001// Data used to draw the "are you sure?" dialogue box when resetting
2002// to defaults.
2003
2004#define VERIFYBOXXORG 66
2005#define VERIFYBOXYORG 88
2006#define PAL_GRAY1 91
2007#define PAL_GRAY2 98
2008#define PAL_GRAY3 105
2009
2010// And the routine to draw it.
2011
2012static void M_DrawDefVerify(void)
2013{
2014 // proff 12/6/98: Drawing of verify box changed for hi-res, it now uses a patch
2015 V_DrawNamePatch(VERIFYBOXXORG,VERIFYBOXYORG,0,"M_VBOX",CR_DEFAULT,VPT_STRETCH);
2016 // The blinking messages is keyed off of the blinking of the
2017 // cursor skull.
2018
2019 if (whichSkull) { // blink the text
2020 strcpy(menu_buffer,"Reset to defaults? (Y or N)");
2021 M_DrawMenuString(VERIFYBOXXORG+8,VERIFYBOXYORG+8,CR_RED);
2022 }
2023}
2024
2025
2026/////////////////////////////
2027//
2028// phares 4/18/98:
2029// M_DrawInstructions writes the instruction text just below the screen title
2030//
2031// cph 2006/08/06 - go back to the Boom version, and then clean up by using
2032// M_DrawStringCentered (much better than all those magic 'x' valies!)
2033
2034static void M_DrawInstructions(void)
2035{
2036 int flags = current_setup_menu[set_menu_itemon].m_flags;
2037
2038 // There are different instruction messages depending on whether you
2039 // are changing an item or just sitting on it.
2040
2041 if (setup_select) {
2042 switch (flags & (S_KEY | S_YESNO | S_WEAP | S_NUM | S_COLOR | S_CRITEM | S_CHAT | S_RESET | S_FILE | S_CHOICE)) {
2043 case S_KEY:
2044 // See if a joystick or mouse button setting is allowed for
2045 // this item.
2046 if (current_setup_menu[set_menu_itemon].m_mouse || current_setup_menu[set_menu_itemon].m_joy)
2047 M_DrawStringCentered(160, 20, CR_SELECT, "Press key or button for this action");
2048 else
2049 M_DrawStringCentered(160, 20, CR_SELECT, "Press key for this action");
2050 break;
2051
2052 case S_YESNO:
2053 M_DrawStringCentered(160, 20, CR_SELECT, "Press ENTER key to toggle");
2054 break;
2055 case S_WEAP:
2056 M_DrawStringCentered(160, 20, CR_SELECT, "Enter weapon number");
2057 break;
2058 case S_NUM:
2059 M_DrawStringCentered(160, 20, CR_SELECT, "Enter value. Press ENTER when finished.");
2060 break;
2061 case S_COLOR:
2062 M_DrawStringCentered(160, 20, CR_SELECT, "Select color and press enter");
2063 break;
2064 case S_CRITEM:
2065 M_DrawStringCentered(160, 20, CR_SELECT, "Enter value");
2066 break;
2067 case S_CHAT:
2068 M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit chat string and Press ENTER");
2069 break;
2070 case S_FILE:
2071 M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit filename and Press ENTER");
2072 break;
2073 case S_CHOICE:
2074 M_DrawStringCentered(160, 20, CR_SELECT, "Press left or right to choose");
2075 break;
2076 case S_RESET:
2077 break;
2078#ifdef SIMPLECHECKS
2079 default:
2080 lprintf(LO_WARN,"Unrecognised menu item type %d", flags);
2081#endif
2082 }
2083 } else {
2084 if (flags & S_RESET)
2085 M_DrawStringCentered(160, 20, CR_HILITE, "Press ENTER key to reset to defaults");
2086 else
2087 M_DrawStringCentered(160, 20, CR_HILITE, "Press Enter to Change");
2088 }
2089}
2090
2091
2092/////////////////////////////
2093//
2094// The Key Binding Screen tables.
2095
2096#define KB_X 160
2097#define KB_PREV 57
2098#define KB_NEXT 310
2099#define KB_Y 31
2100
2101// phares 4/16/98:
2102// X,Y position of reset button. This is the same for every screen, and is
2103// only defined once here.
2104
2105#define X_BUTTON 301
2106#define Y_BUTTON 3
2107
2108// Definitions of the (in this case) four key binding screens.
2109
2110setup_menu_t keys_settings1[];
2111setup_menu_t keys_settings2[];
2112setup_menu_t keys_settings3[];
2113setup_menu_t keys_settings4[];
2114
2115// The table which gets you from one screen table to the next.
2116
2117setup_menu_t* keys_settings[] =
2118{
2119 keys_settings1,
2120 keys_settings2,
2121 keys_settings3,
2122 keys_settings4,
2123 NULL
2124};
2125
2126int mult_screens_index; // the index of the current screen in a set
2127
2128// Here's an example from this first screen, with explanations.
2129//
2130// {
2131// "STRAFE", // The description of the item ('strafe' key)
2132// S_KEY, // This is a key binding item
2133// m_scrn, // It belongs to the m_scrn group. Its key cannot be
2134// // bound to two items in this group.
2135// KB_X, // The X offset of the start of the right-hand side
2136// KB_Y+ 8*8, // The Y offset of the start of the right-hand side.
2137// // Always given in multiples off a baseline.
2138// &key_strafe, // The variable that holds the key value bound to this
2139// OR a string that holds the config variable name.
2140// OR a pointer to another setup_menu
2141// &mousebstrafe, // The variable that holds the mouse button bound to
2142 // this. If zero, no mouse button can be bound here.
2143// &joybstrafe, // The variable that holds the joystick button bound to
2144 // this. If zero, no mouse button can be bound here.
2145// }
2146
2147// The first Key Binding screen table.
2148// Note that the Y values are ascending. If you need to add something to
2149// this table, (well, this one's not a good example, because it's full)
2150// you need to make sure the Y values still make sense so everything gets
2151// displayed.
2152//
2153// Note also that the first screen of each set has a line for the reset
2154// button. If there is more than one screen in a set, the others don't get
2155// the reset button.
2156//
2157// Note also that this screen has a "NEXT ->" line. This acts like an
2158// item, in that 'activating' it moves you along to the next screen. If
2159// there's a "<- PREV" item on a screen, it behaves similarly, moving you
2160// to the previous screen. If you leave these off, you can't move from
2161// screen to screen.
2162
2163setup_menu_t keys_settings1[] = // Key Binding screen strings
2164{
2165 {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2166 {"FORWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+1*8,{&key_up},&mousebforward},
2167 {"BACKWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+2*8,{&key_down}},
2168 {"TURN LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+3*8,{&key_left}},
2169 {"TURN RIGHT" ,S_KEY ,m_scrn,KB_X,KB_Y+4*8,{&key_right}},
2170 {"RUN" ,S_KEY ,m_scrn,KB_X,KB_Y+5*8,{&key_speed},0,&joybspeed},
2171 {"STRAFE LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+6*8,{&key_strafeleft}},
2172 {"STRAFE RIGHT",S_KEY ,m_scrn,KB_X,KB_Y+7*8,{&key_straferight}},
2173 {"STRAFE" ,S_KEY ,m_scrn,KB_X,KB_Y+8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
2174 {"AUTORUN" ,S_KEY ,m_scrn,KB_X,KB_Y+9*8,{&key_autorun}},
2175 {"180 TURN" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_reverse}},
2176 {"USE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_use},&mousebforward,&joybuse},
2177
2178 {"MENUS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2179 {"NEXT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+13*8,{&key_menu_down}},
2180 {"PREV ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+14*8,{&key_menu_up}},
2181 {"LEFT" ,S_KEY ,m_menu,KB_X,KB_Y+15*8,{&key_menu_left}},
2182 {"RIGHT" ,S_KEY ,m_menu,KB_X,KB_Y+16*8,{&key_menu_right}},
2183 {"BACKSPACE" ,S_KEY ,m_menu,KB_X,KB_Y+17*8,{&key_menu_backspace}},
2184 {"SELECT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+18*8,{&key_menu_enter}},
2185 {"EXIT" ,S_KEY ,m_menu,KB_X,KB_Y+19*8,{&key_menu_escape}},
2186
2187 // Button for resetting to defaults
2188 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2189
2190 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings2}},
2191
2192 // Final entry
2193 {0,S_SKIP|S_END,m_null}
2194
2195};
2196
2197setup_menu_t keys_settings2[] = // Key Binding screen strings
2198{
2199 {"SCREEN" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2200
2201 // phares 4/13/98:
2202 // key_help and key_escape can no longer be rebound. This keeps the
2203 // player from getting themselves in a bind where they can't remember how
2204 // to get to the menus, and can't remember how to get to the help screen
2205 // to give them a clue as to how to get to the menus. :)
2206
2207 // Also, the keys assigned to these functions cannot be bound to other
2208 // functions. Introduce an S_KEEP flag to show that you cannot swap this
2209 // key with other keys in the same 'group'. (m_scrn, etc.)
2210
2211 {"HELP" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_help}},
2212 {"MENU" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_escape}},
2213 // killough 10/98: hotkey for entering setup menu:
2214 {"SETUP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_setup}},
2215 {"PAUSE" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_pause}},
2216 {"AUTOMAP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_map}},
2217 {"VOLUME" ,S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_soundvolume}},
2218 {"HUD" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_hud}},
2219 {"MESSAGES" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_messages}},
2220 {"GAMMA FIX" ,S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_gamma}},
2221 {"SPY" ,S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_spy}},
2222 {"LARGER VIEW" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_zoomin}},
2223 {"SMALLER VIEW",S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_zoomout}},
2224 {"SCREENSHOT" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_screenshot}},
2225 {"GAME" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2226 {"SAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_savegame}},
2227 {"LOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&key_loadgame}},
2228 {"QUICKSAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&key_quicksave}},
2229 {"QUICKLOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&key_quickload}},
2230 {"END GAME" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&key_endgame}},
2231 {"QUIT" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_quit}},
2232 {"<- PREV", S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings1}},
2233 {"NEXT ->", S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings3}},
2234
2235 // Final entry
2236
2237 {0,S_SKIP|S_END,m_null}
2238};
2239
2240setup_menu_t keys_settings3[] = // Key Binding screen strings
2241{
2242 {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2243 {"FIST" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_weapon1}},
2244 {"PISTOL" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_weapon2}},
2245 {"SHOTGUN" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_weapon3}},
2246 {"CHAINGUN",S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_weapon4}},
2247 {"ROCKET" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_weapon5}},
2248 {"PLASMA" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_weapon6}},
2249 {"BFG", S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_weapon7}},
2250 {"CHAINSAW",S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_weapon8}},
2251 {"SSG" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_weapon9}},
2252 {"BEST" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_weapontoggle}},
2253 {"FIRE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_fire},&mousebfire,&joybfire},
2254
2255 {"<- PREV",S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings2}},
2256 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings4}},
2257
2258 // Final entry
2259
2260 {0,S_SKIP|S_END,m_null}
2261
2262};
2263
2264setup_menu_t keys_settings4[] = // Key Binding screen strings
2265{
2266 {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
2267 {"FOLLOW" ,S_KEY ,m_map ,KB_X,KB_Y+ 1*8,{&key_map_follow}},
2268 {"ZOOM IN" ,S_KEY ,m_map ,KB_X,KB_Y+ 2*8,{&key_map_zoomin}},
2269 {"ZOOM OUT" ,S_KEY ,m_map ,KB_X,KB_Y+ 3*8,{&key_map_zoomout}},
2270 {"SHIFT UP" ,S_KEY ,m_map ,KB_X,KB_Y+ 4*8,{&key_map_up}},
2271 {"SHIFT DOWN" ,S_KEY ,m_map ,KB_X,KB_Y+ 5*8,{&key_map_down}},
2272 {"SHIFT LEFT" ,S_KEY ,m_map ,KB_X,KB_Y+ 6*8,{&key_map_left}},
2273 {"SHIFT RIGHT",S_KEY ,m_map ,KB_X,KB_Y+ 7*8,{&key_map_right}},
2274 {"MARK PLACE" ,S_KEY ,m_map ,KB_X,KB_Y+ 8*8,{&key_map_mark}},
2275 {"CLEAR MARKS",S_KEY ,m_map ,KB_X,KB_Y+ 9*8,{&key_map_clear}},
2276 {"FULL/ZOOM" ,S_KEY ,m_map ,KB_X,KB_Y+10*8,{&key_map_gobig}},
2277 {"GRID" ,S_KEY ,m_map ,KB_X,KB_Y+11*8,{&key_map_grid}},
2278
2279 {"CHATTING" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
2280 {"BEGIN CHAT" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_chat}},
2281 {"PLAYER 1" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&destination_keys[0]}},
2282 {"PLAYER 2" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&destination_keys[1]}},
2283 {"PLAYER 3" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&destination_keys[2]}},
2284 {"PLAYER 4" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&destination_keys[3]}},
2285 {"BACKSPACE" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_backspace}},
2286 {"ENTER" ,S_KEY ,m_scrn,KB_X,KB_Y+19*8,{&key_enter}},
2287
2288 {"<- PREV" ,S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings3}},
2289
2290 // Final entry
2291
2292 {0,S_SKIP|S_END,m_null}
2293
2294};
2295
2296// Setting up for the Key Binding screen. Turn on flags, set pointers,
2297// locate the first item on the screen where the cursor is allowed to
2298// land.
2299
2300void M_KeyBindings(int choice)
2301{
2302 M_SetupNextMenu(&KeybndDef);
2303
2304 setup_active = true;
2305 setup_screen = ss_keys;
2306 set_keybnd_active = true;
2307 setup_select = false;
2308 default_verify = false;
2309 setup_gather = false;
2310 mult_screens_index = 0;
2311 current_setup_menu = keys_settings[0];
2312 set_menu_itemon = 0;
2313 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2314 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2315}
2316
2317// The drawing part of the Key Bindings Setup initialization. Draw the
2318// background, title, instruction line, and items.
2319
2320void M_DrawKeybnd(void)
2321
2322{
2323 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2324
2325 // Set up the Key Binding screen
2326
2327 M_DrawBackground("FLOOR4_6", 0); // Draw background
2328 // proff/nicolas 09/20/98 -- changed for hi-res
2329 V_DrawNamePatch(84, 2, 0, "M_KEYBND", CR_DEFAULT, VPT_STRETCH);
2330 M_DrawInstructions();
2331 M_DrawScreenItems(current_setup_menu);
2332
2333 // If the Reset Button has been selected, an "Are you sure?" message
2334 // is overlayed across everything else.
2335
2336 if (default_verify)
2337 M_DrawDefVerify();
2338}
2339
2340/////////////////////////////
2341//
2342// The Weapon Screen tables.
2343
2344#define WP_X 203
2345#define WP_Y 33
2346
2347// There's only one weapon settings screen (for now). But since we're
2348// trying to fit a common description for screens, it gets a setup_menu_t,
2349// which only has one screen definition in it.
2350//
2351// Note that this screen has no PREV or NEXT items, since there are no
2352// neighboring screens.
2353
2354enum { // killough 10/98: enum for y-offset info
2355 weap_recoil,
2356 weap_bobbing,
2357 weap_bfg,
2358 weap_stub1,
2359 weap_pref1,
2360 weap_pref2,
2361 weap_pref3,
2362 weap_pref4,
2363 weap_pref5,
2364 weap_pref6,
2365 weap_pref7,
2366 weap_pref8,
2367 weap_pref9,
2368 weap_stub2,
2369 weap_toggle,
2370 weap_toggle2,
2371};
2372
2373setup_menu_t weap_settings1[];
2374
2375setup_menu_t* weap_settings[] =
2376{
2377 weap_settings1,
2378 NULL
2379};
2380
2381setup_menu_t weap_settings1[] = // Weapons Settings screen
2382{
2383 {"ENABLE RECOIL", S_YESNO,m_null,WP_X, WP_Y+ weap_recoil*8, {"weapon_recoil"}},
2384 {"ENABLE BOBBING",S_YESNO,m_null,WP_X, WP_Y+weap_bobbing*8, {"player_bobbing"}},
2385
2386 {"1ST CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref1*8, {"weapon_choice_1"}},
2387 {"2nd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref2*8, {"weapon_choice_2"}},
2388 {"3rd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref3*8, {"weapon_choice_3"}},
2389 {"4th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref4*8, {"weapon_choice_4"}},
2390 {"5th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref5*8, {"weapon_choice_5"}},
2391 {"6th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref6*8, {"weapon_choice_6"}},
2392 {"7th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref7*8, {"weapon_choice_7"}},
2393 {"8th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref8*8, {"weapon_choice_8"}},
2394 {"9th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref9*8, {"weapon_choice_9"}},
2395
2396 {"Enable Fist/Chainsaw\n& SG/SSG toggle", S_YESNO, m_null, WP_X,
2397 WP_Y+ weap_toggle*8, {"doom_weapon_toggles"}},
2398
2399 // Button for resetting to defaults
2400 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2401
2402 // Final entry
2403 {0,S_SKIP|S_END,m_null}
2404
2405};
2406
2407// Setting up for the Weapons screen. Turn on flags, set pointers,
2408// locate the first item on the screen where the cursor is allowed to
2409// land.
2410
2411void M_Weapons(int choice)
2412{
2413 M_SetupNextMenu(&WeaponDef);
2414
2415 setup_active = true;
2416 setup_screen = ss_weap;
2417 set_weapon_active = true;
2418 setup_select = false;
2419 default_verify = false;
2420 setup_gather = false;
2421 mult_screens_index = 0;
2422 current_setup_menu = weap_settings[0];
2423 set_menu_itemon = 0;
2424 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2425 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2426}
2427
2428
2429// The drawing part of the Weapons Setup initialization. Draw the
2430// background, title, instruction line, and items.
2431
2432void M_DrawWeapons(void)
2433{
2434 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2435
2436 M_DrawBackground("FLOOR4_6", 0); // Draw background
2437 // proff/nicolas 09/20/98 -- changed for hi-res
2438 V_DrawNamePatch(109, 2, 0, "M_WEAP", CR_DEFAULT, VPT_STRETCH);
2439 M_DrawInstructions();
2440 M_DrawScreenItems(current_setup_menu);
2441
2442 // If the Reset Button has been selected, an "Are you sure?" message
2443 // is overlayed across everything else.
2444
2445 if (default_verify)
2446 M_DrawDefVerify();
2447}
2448
2449/////////////////////////////
2450//
2451// The Status Bar / HUD tables.
2452
2453#define ST_X 203
2454#define ST_Y 31
2455
2456// Screen table definitions
2457
2458setup_menu_t stat_settings1[];
2459
2460setup_menu_t* stat_settings[] =
2461{
2462 stat_settings1,
2463 NULL
2464};
2465
2466setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen
2467{
2468 {"STATUS BAR" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 1*8 },
2469
2470 {"USE RED NUMBERS" ,S_YESNO, m_null,ST_X,ST_Y+ 2*8, {"sts_always_red"}},
2471 {"GRAY %" ,S_YESNO, m_null,ST_X,ST_Y+ 3*8, {"sts_pct_always_gray"}},
2472 {"SINGLE KEY DISPLAY",S_YESNO, m_null,ST_X,ST_Y+ 4*8, {"sts_traditional_keys"}},
2473
2474 {"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 6*8},
2475
2476 {"HIDE SECRETS" ,S_YESNO ,m_null,ST_X,ST_Y+ 7*8, {"hud_nosecrets"}},
2477 {"HEALTH LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+ 8*8, {"health_red"}},
2478 {"HEALTH OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+ 9*8, {"health_yellow"}},
2479 {"HEALTH GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+10*8, {"health_green"}},
2480 {"ARMOR LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+11*8, {"armor_red"}},
2481 {"ARMOR OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+12*8, {"armor_yellow"}},
2482 {"ARMOR GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+13*8, {"armor_green"}},
2483 {"AMMO LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+14*8, {"ammo_red"}},
2484 {"AMMO OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+15*8, {"ammo_yellow"}},
2485
2486 // Button for resetting to defaults
2487 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2488
2489 // Final entry
2490 {0,S_SKIP|S_END,m_null}
2491};
2492
2493// Setting up for the Status Bar / HUD screen. Turn on flags, set pointers,
2494// locate the first item on the screen where the cursor is allowed to
2495// land.
2496
2497void M_StatusBar(int choice)
2498{
2499 M_SetupNextMenu(&StatusHUDDef);
2500
2501 setup_active = true;
2502 setup_screen = ss_stat;
2503 set_status_active = true;
2504 setup_select = false;
2505 default_verify = false;
2506 setup_gather = false;
2507 mult_screens_index = 0;
2508 current_setup_menu = stat_settings[0];
2509 set_menu_itemon = 0;
2510 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2511 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2512}
2513
2514
2515// The drawing part of the Status Bar / HUD Setup initialization. Draw the
2516// background, title, instruction line, and items.
2517
2518void M_DrawStatusHUD(void)
2519
2520{
2521 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2522
2523 M_DrawBackground("FLOOR4_6", 0); // Draw background
2524 // proff/nicolas 09/20/98 -- changed for hi-res
2525 V_DrawNamePatch(59, 2, 0, "M_STAT", CR_DEFAULT, VPT_STRETCH);
2526 M_DrawInstructions();
2527 M_DrawScreenItems(current_setup_menu);
2528
2529 // If the Reset Button has been selected, an "Are you sure?" message
2530 // is overlayed across everything else.
2531
2532 if (default_verify)
2533 M_DrawDefVerify();
2534}
2535
2536
2537/////////////////////////////
2538//
2539// The Automap tables.
2540
2541#define AU_X 250
2542#define AU_Y 31
2543#define AU_PREV KB_PREV
2544#define AU_NEXT KB_NEXT
2545
2546setup_menu_t auto_settings1[];
2547setup_menu_t auto_settings2[];
2548
2549setup_menu_t* auto_settings[] =
2550{
2551 auto_settings1,
2552 auto_settings2,
2553 NULL
2554};
2555
2556setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen
2557{
2558 {"background", S_COLOR, m_null, AU_X, AU_Y, {"mapcolor_back"}},
2559 {"grid lines", S_COLOR, m_null, AU_X, AU_Y + 1*8, {"mapcolor_grid"}},
2560 {"normal 1s wall", S_COLOR, m_null,AU_X,AU_Y+ 2*8, {"mapcolor_wall"}},
2561 {"line at floor height change", S_COLOR, m_null, AU_X, AU_Y+ 3*8, {"mapcolor_fchg"}},
2562 {"line at ceiling height change" ,S_COLOR,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_cchg"}},
2563 {"line at sector with floor = ceiling",S_COLOR,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_clsd"}},
2564 {"red key" ,S_COLOR,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_rkey"}},
2565 {"blue key" ,S_COLOR,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_bkey"}},
2566 {"yellow key" ,S_COLOR,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_ykey"}},
2567 {"red door" ,S_COLOR,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_rdor"}},
2568 {"blue door" ,S_COLOR,m_null,AU_X,AU_Y+10*8, {"mapcolor_bdor"}},
2569 {"yellow door" ,S_COLOR,m_null,AU_X,AU_Y+11*8, {"mapcolor_ydor"}},
2570
2571 {"AUTOMAP LEVEL TITLE COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+13*8, {"hudcolor_titl"}},
2572 {"AUTOMAP COORDINATES COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+14*8, {"hudcolor_xyco"}},
2573
2574 {"Show Secrets only after entering",S_YESNO,m_null,AU_X,AU_Y+15*8, {"map_secret_after"}},
2575
2576 {"Show coordinates of automap pointer",S_YESNO,m_null,AU_X,AU_Y+16*8, {"map_point_coord"}}, // killough 10/98
2577
2578 // Button for resetting to defaults
2579 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2580
2581 {"NEXT ->",S_SKIP|S_NEXT,m_null,AU_NEXT,AU_Y+20*8, {auto_settings2}},
2582
2583 // Final entry
2584 {0,S_SKIP|S_END,m_null}
2585
2586};
2587
2588setup_menu_t auto_settings2[] = // 2nd AutoMap Settings screen
2589{
2590 {"teleporter line" ,S_COLOR ,m_null,AU_X,AU_Y, {"mapcolor_tele"}},
2591 {"secret sector boundary" ,S_COLOR ,m_null,AU_X,AU_Y+ 1*8, {"mapcolor_secr"}},
2592 //jff 4/23/98 add exit line to automap
2593 {"exit line" ,S_COLOR ,m_null,AU_X,AU_Y+ 2*8, {"mapcolor_exit"}},
2594 {"computer map unseen line" ,S_COLOR ,m_null,AU_X,AU_Y+ 3*8, {"mapcolor_unsn"}},
2595 {"line w/no floor/ceiling changes",S_COLOR ,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_flat"}},
2596 {"general sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_sprt"}},
2597 {"countable enemy sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_enemy"}}, // cph 2006/06/30
2598 {"countable item sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_item"}}, // mead 3/4/2003
2599 {"crosshair" ,S_COLOR ,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_hair"}},
2600 {"single player arrow" ,S_COLOR ,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_sngl"}},
2601 {"your colour in multiplayer" ,S_COLOR ,m_null,AU_X,AU_Y+10*8, {"mapcolor_me"}},
2602
2603 {"friends" ,S_COLOR ,m_null,AU_X,AU_Y+12*8, {"mapcolor_frnd"}}, // killough 8/8/98
2604
2605 {"<- PREV",S_SKIP|S_PREV,m_null,AU_PREV,AU_Y+20*8, {auto_settings1}},
2606
2607 // Final entry
2608
2609 {0,S_SKIP|S_END,m_null}
2610
2611};
2612
2613
2614// Setting up for the Automap screen. Turn on flags, set pointers,
2615// locate the first item on the screen where the cursor is allowed to
2616// land.
2617
2618void M_Automap(int choice)
2619{
2620 M_SetupNextMenu(&AutoMapDef);
2621
2622 setup_active = true;
2623 setup_screen = ss_auto;
2624 set_auto_active = true;
2625 setup_select = false;
2626 colorbox_active = false;
2627 default_verify = false;
2628 setup_gather = false;
2629 set_menu_itemon = 0;
2630 mult_screens_index = 0;
2631 current_setup_menu = auto_settings[0];
2632 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2633 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2634}
2635
2636// Data used by the color palette that is displayed for the player to
2637// select colors.
2638
2639int color_palette_x; // X position of the cursor on the color palette
2640int color_palette_y; // Y position of the cursor on the color palette
2641byte palette_background[16*(CHIP_SIZE+1)+8];
2642
2643// M_DrawColPal() draws the color palette when the user needs to select a
2644// color.
2645
2646// phares 4/1/98: now uses a single lump for the palette instead of
2647// building the image out of individual paint chips.
2648
2649static void M_DrawColPal(void)
2650{
2651 int cpx, cpy;
2652
2653 // Draw a background, border, and paint chips
2654
2655 // proff/nicolas 09/20/98 -- changed for hi-res
2656 // CPhipps - patch drawing updated
2657 V_DrawNamePatch(COLORPALXORIG-5, COLORPALYORIG-5, 0, "M_COLORS", CR_DEFAULT, VPT_STRETCH);
2658
2659 // Draw the cursor around the paint chip
2660 // (cpx,cpy) is the upper left-hand corner of the paint chip
2661
2662 cpx = COLORPALXORIG+color_palette_x*(CHIP_SIZE+1)-1;
2663 cpy = COLORPALYORIG+color_palette_y*(CHIP_SIZE+1)-1;
2664 // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
2665 V_DrawNamePatch(cpx,cpy,0,"M_PALSEL",CR_DEFAULT,VPT_STRETCH); // PROFF_GL_FIX
2666}
2667
2668// The drawing part of the Automap Setup initialization. Draw the
2669// background, title, instruction line, and items.
2670
2671void M_DrawAutoMap(void)
2672
2673{
2674 inhelpscreens = true; // killough 4/6/98: Force status bar redraw
2675
2676 M_DrawBackground("FLOOR4_6", 0); // Draw background
2677 // CPhipps - patch drawing updated
2678 V_DrawNamePatch(109, 2, 0, "M_AUTO", CR_DEFAULT, VPT_STRETCH);
2679 M_DrawInstructions();
2680 M_DrawScreenItems(current_setup_menu);
2681
2682 // If a color is being selected, need to show color paint chips
2683
2684 if (colorbox_active)
2685 M_DrawColPal();
2686
2687 // If the Reset Button has been selected, an "Are you sure?" message
2688 // is overlayed across everything else.
2689
2690 else if (default_verify)
2691 M_DrawDefVerify();
2692}
2693
2694
2695/////////////////////////////
2696//
2697// The Enemies table.
2698
2699#define E_X 250
2700#define E_Y 31
2701
2702setup_menu_t enem_settings1[];
2703
2704setup_menu_t* enem_settings[] =
2705{
2706 enem_settings1,
2707 NULL
2708};
2709
2710enum {
2711 enem_infighting,
2712
2713 enem_remember = 1,
2714
2715 enem_backing,
2716 enem_monkeys,
2717 enem_avoid_hazards,
2718 enem_friction,
2719 enem_help_friends,
2720
2721#ifdef DOGS
2722 enem_helpers,
2723#endif
2724
2725 enem_distfriend,
2726
2727#ifdef DOGS
2728 enem_dog_jumping,
2729#endif
2730
2731 enem_end
2732};
2733
2734setup_menu_t enem_settings1[] = // Enemy Settings screen
2735{
2736 // killough 7/19/98
2737 {"Monster Infighting When Provoked",S_YESNO,m_null,E_X,E_Y+ enem_infighting*8, {"monster_infighting"}},
2738
2739 {"Remember Previous Enemy",S_YESNO,m_null,E_X,E_Y+ enem_remember*8, {"monsters_remember"}},
2740
2741 // killough 9/8/98
2742 {"Monster Backing Out",S_YESNO,m_null,E_X,E_Y+ enem_backing*8, {"monster_backing"}},
2743
2744 {"Climb Steep Stairs", S_YESNO,m_null,E_X,E_Y+enem_monkeys*8, {"monkeys"}},
2745
2746 // killough 9/9/98
2747 {"Intelligently Avoid Hazards",S_YESNO,m_null,E_X,E_Y+ enem_avoid_hazards*8, {"monster_avoid_hazards"}},
2748
2749 // killough 10/98
2750 {"Affected by Friction",S_YESNO,m_null,E_X,E_Y+ enem_friction*8, {"monster_friction"}},
2751
2752 {"Rescue Dying Friends",S_YESNO,m_null,E_X,E_Y+ enem_help_friends*8, {"help_friends"}},
2753
2754#ifdef DOGS
2755 // killough 7/19/98
2756 {"Number Of Single-Player Helper Dogs",S_NUM|S_LEVWARN,m_null,E_X,E_Y+ enem_helpers*8, {"player_helpers"}},
2757
2758 // killough 8/8/98
2759 {"Distance Friends Stay Away",S_NUM,m_null,E_X,E_Y+ enem_distfriend*8, {"friend_distance"}},
2760
2761 {"Allow dogs to jump down",S_YESNO,m_null,E_X,E_Y+ enem_dog_jumping*8, {"dog_jumping"}},
2762#endif
2763
2764 // Button for resetting to defaults
2765 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2766
2767 // Final entry
2768 {0,S_SKIP|S_END,m_null}
2769
2770};
2771
2772/////////////////////////////
2773
2774// Setting up for the Enemies screen. Turn on flags, set pointers,
2775// locate the first item on the screen where the cursor is allowed to
2776// land.
2777
2778void M_Enemy(int choice)
2779{
2780 M_SetupNextMenu(&EnemyDef);
2781
2782 setup_active = true;
2783 setup_screen = ss_enem;
2784 set_enemy_active = true;
2785 setup_select = false;
2786 default_verify = false;
2787 setup_gather = false;
2788 mult_screens_index = 0;
2789 current_setup_menu = enem_settings[0];
2790 set_menu_itemon = 0;
2791 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
2792 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
2793}
2794
2795// The drawing part of the Enemies Setup initialization. Draw the
2796// background, title, instruction line, and items.
2797
2798void M_DrawEnemy(void)
2799
2800{
2801 inhelpscreens = true;
2802
2803 M_DrawBackground("FLOOR4_6", 0); // Draw background
2804 // proff/nicolas 09/20/98 -- changed for hi-res
2805 V_DrawNamePatch(114, 2, 0, "M_ENEM", CR_DEFAULT, VPT_STRETCH);
2806 M_DrawInstructions();
2807 M_DrawScreenItems(current_setup_menu);
2808
2809 // If the Reset Button has been selected, an "Are you sure?" message
2810 // is overlayed across everything else.
2811
2812 if (default_verify)
2813 M_DrawDefVerify();
2814}
2815
2816
2817/////////////////////////////
2818//
2819// The General table.
2820// killough 10/10/98
2821
2822extern int usejoystick, usemouse, default_mus_card, default_snd_card;
2823extern int detect_voices, realtic_clock_rate, tran_filter_pct;
2824
2825setup_menu_t gen_settings1[], gen_settings2[], gen_settings3[];
2826
2827setup_menu_t* gen_settings[] =
2828{
2829 gen_settings1,
2830 gen_settings2,
2831 gen_settings3,
2832 NULL
2833};
2834
2835enum {
2836 general_trans,
2837 general_transpct,
2838 general_fullscreen,
2839 general_videomode,
2840// general_pcx,
2841// general_diskicon,
2842 general_uncapped,
2843};
2844
2845enum {
2846 general_gl_texfilter,
2847 general_gl_texformat,
2848 general_flooroffset,
2849};
2850
2851enum {
2852// general_sndcard,
2853// general_muscard,
2854// general_detvoices,
2855 general_sndchan,
2856 general_pitch
2857};
2858
2859#define G_X 250
2860#define G_YA 44
2861#define G_YA2 (G_YA+9*8)
2862#define G_YA3 (G_YA2+5*8)
2863#define GF_X 76
2864
2865static const char *videomodes[] = {"8bit","15bit","16bit",
2866 "32bit","OpenGL", NULL};
2867
2868static const char *gltexfilters[] = {"GL_NEAREST","GL_LINEAR",
2869 "GL_LINEAR_MIPMAP_LINEAR",
2870 NULL};
2871
2872static const char *gltexformats[] = {"GL_RGBA","GL_RGB5_A1",
2873 "GL_RGBA4", NULL};
2874
2875setup_menu_t gen_settings1[] = { // General Settings screen1
2876
2877 {"Video" ,S_SKIP|S_TITLE, m_null, G_X, G_YA - 12},
2878
2879 {"Enable Translucency", S_YESNO, m_null, G_X,
2880 G_YA + general_trans*8, {"translucency"}, 0, 0, M_Trans},
2881
2882 {"Translucency filter percentage", S_NUM, m_null, G_X,
2883 G_YA + general_transpct*8, {"tran_filter_pct"}, 0, 0, M_Trans},
2884
2885 {"Fullscreen Video mode", S_YESNO|S_PRGWARN, m_null, G_X,
2886 G_YA + general_fullscreen*8, {"use_fullscreen"}, 0, 0, NULL},
2887
2888 {"Video mode", S_CHOICE|S_PRGWARN, m_null, G_X,
2889 G_YA + general_videomode*8, {"videomode"}, 0, 0, NULL, videomodes},
2890
2891 {"Uncapped Framerate", S_YESNO, m_null, G_X,
2892 G_YA + general_uncapped*8, {"uncapped_framerate"}},
2893
2894#ifdef GL_DOOM
2895 {"OpenGL", S_SKIP|S_TITLE, m_null, G_X, G_YA2 - 12},
2896
2897 {"Texture filter", S_CHOICE|S_PRGWARN, m_null, G_X,
2898 G_YA2 + general_gl_texfilter*8, {"gl_tex_filter_string"}, 0, 0, NULL, gltexfilters},
2899
2900 {"Texture format", S_CHOICE|S_PRGWARN, m_null, G_X,
2901 G_YA2 + general_gl_texformat*8, {"gl_tex_format_string"}, 0, 0, NULL, gltexformats},
2902
2903 {"Item out of Floor offset", S_NUM, m_null, G_X,
2904 G_YA2 + general_flooroffset*8, {"gl_sprite_offset"}},
2905#endif
2906
2907#if 0
2908 {"PCX instead of BMP for screenshots", S_YESNO, m_null, G_X,
2909 G_YA + general_pcx*8, {"screenshot_pcx"}},
2910#endif
2911
2912#if 0 // MBF
2913 {"Flash Icon During Disk IO", S_YESNO, m_null, G_X,
2914 G_YA + general_diskicon*8, {"disk_icon"}},
2915#endif
2916
2917 {"Sound & Music", S_SKIP|S_TITLE, m_null, G_X, G_YA3 - 12},
2918#if 0 // MBF
2919 {"Sound Card", S_NUM|S_PRGWARN, m_null, G_X,
2920 G_YA2 + general_sndcard*8, {"sound_card"}},
2921
2922 {"Music Card", S_NUM|S_PRGWARN, m_null, G_X,
2923 G_YA2 + general_muscard*8, {"music_card"}},
2924
2925 {"Autodetect Number of Voices", S_YESNO|S_PRGWARN, m_null, G_X,
2926 G_YA2 + general_detvoices*8, {"detect_voices"}},
2927#endif
2928
2929 {"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, G_X,
2930 G_YA3 + general_sndchan*8, {"snd_channels"}},
2931
2932 {"Enable v1.1 Pitch Effects", S_YESNO, m_null, G_X,
2933 G_YA3 + general_pitch*8, {"pitched_sounds"}},
2934
2935 // Button for resetting to defaults
2936 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
2937
2938 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings2}},
2939
2940 // Final entry
2941 {0,S_SKIP|S_END,m_null}
2942};
2943
2944enum {
2945 general_mouse,
2946 general_joy,
2947 general_leds
2948};
2949
2950enum {
2951 general_wad1,
2952 general_wad2,
2953 general_deh1,
2954 general_deh2
2955};
2956
2957enum {
2958 general_corpse,
2959 general_realtic,
2960 general_smooth,
2961 general_smoothfactor,
2962 general_defskill,
2963};
2964
2965#define G_YB 44
2966#define G_YB1 (G_YB+44)
2967#define G_YB2 (G_YB1+52)
2968
2969static const char *gen_skillstrings[] = {
2970 // Dummy first option because defaultskill is 1-based
2971 "", "ITYTD", "HNTR", "HMP", "UV", "NM", NULL
2972};
2973
2974setup_menu_t gen_settings2[] = { // General Settings screen2
2975
2976 {"Input Devices" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
2977
2978 {"Enable Mouse", S_YESNO, m_null, G_X,
2979 G_YB + general_mouse*8, {"use_mouse"}},
2980
2981 {"Enable Joystick", S_YESNO, m_null, G_X,
2982 G_YB + general_joy*8, {"use_joystick"}},
2983
2984 {"Files Preloaded at Game Startup",S_SKIP|S_TITLE, m_null, G_X,
2985 G_YB1 - 12},
2986
2987 {"WAD # 1", S_FILE, m_null, GF_X, G_YB1 + general_wad1*8, {"wadfile_1"}},
2988
2989 {"WAD #2", S_FILE, m_null, GF_X, G_YB1 + general_wad2*8, {"wadfile_2"}},
2990
2991 {"DEH/BEX # 1", S_FILE, m_null, GF_X, G_YB1 + general_deh1*8, {"dehfile_1"}},
2992
2993 {"DEH/BEX #2", S_FILE, m_null, GF_X, G_YB1 + general_deh2*8, {"dehfile_2"}},
2994
2995 {"Miscellaneous" ,S_SKIP|S_TITLE, m_null, G_X, G_YB2 - 12},
2996
2997 {"Maximum number of player corpses", S_NUM|S_PRGWARN, m_null, G_X,
2998 G_YB2 + general_corpse*8, {"max_player_corpse"}},
2999
3000 {"Game speed, percentage of normal", S_NUM|S_PRGWARN, m_null, G_X,
3001 G_YB2 + general_realtic*8, {"realtic_clock_rate"}},
3002
3003 {"Smooth Demo Playback", S_YESNO, m_null, G_X,
3004 G_YB2 + general_smooth*8, {"demo_smoothturns"}, 0, 0, M_ChangeDemoSmoothTurns},
3005
3006 {"Smooth Demo Playback Factor", S_NUM, m_null, G_X,
3007 G_YB2 + general_smoothfactor*8, {"demo_smoothturnsfactor"}, 0, 0, M_ChangeDemoSmoothTurns},
3008
3009 {"Default skill level", S_CHOICE, m_null, G_X,
3010 G_YB2 + general_defskill*8, {"default_skill"}, 0, 0, NULL, gen_skillstrings},
3011
3012 {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings1}},
3013
3014 {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings3}},
3015
3016 // Final entry
3017
3018 {0,S_SKIP|S_END,m_null}
3019};
3020
3021enum {
3022 general_filterwall,
3023 general_filterfloor,
3024 general_filtersprite,
3025 general_filterpatch,
3026 general_filterz,
3027 general_filter_threshold,
3028 general_spriteedges,
3029 general_patchedges,
3030 general_hom,
3031};
3032
3033#define G_YC 44
3034
3035static const char *renderfilters[] = {"none", "point", "linear", "rounded"};
3036static const char *edgetypes[] = {"jagged", "sloped"};
3037
3038setup_menu_t gen_settings3[] = { // General Settings screen2
3039
3040 {"Renderer settings" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
3041
3042 {"Filter for walls", S_CHOICE, m_null, G_X,
3043 G_YC + general_filterwall*8, {"filter_wall"}, 0, 0, NULL, renderfilters},
3044
3045 {"Filter for floors/ceilings", S_CHOICE, m_null, G_X,
3046 G_YC + general_filterfloor*8, {"filter_floor"}, 0, 0, NULL, renderfilters},
3047
3048 {"Filter for sprites", S_CHOICE, m_null, G_X,
3049 G_YC + general_filtersprite*8, {"filter_sprite"}, 0, 0, NULL, renderfilters},
3050
3051 {"Filter for patches", S_CHOICE, m_null, G_X,
3052 G_YC + general_filterpatch*8, {"filter_patch"}, 0, 0, NULL, renderfilters},
3053
3054 {"Filter for lighting", S_CHOICE, m_null, G_X,
3055 G_YC + general_filterz*8, {"filter_z"}, 0, 0, NULL, renderfilters},
3056
3057 {"Drawing of sprite edges", S_CHOICE, m_null, G_X,
3058 G_YC + general_spriteedges*8, {"sprite_edges"}, 0, 0, NULL, edgetypes},
3059
3060 {"Drawing of patch edges", S_CHOICE, m_null, G_X,
3061 G_YC + general_patchedges*8, {"patch_edges"}, 0, 0, NULL, edgetypes},
3062
3063 {"Flashing HOM indicator", S_YESNO, m_null, G_X,
3064 G_YC + general_hom*8, {"flashing_hom"}},
3065
3066 {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings2}},
3067
3068 // Final entry
3069
3070 {0,S_SKIP|S_END,m_null}
3071};
3072
3073void M_Trans(void) // To reset translucency after setting it in menu
3074{
3075 general_translucency = default_translucency; //e6y: Fix for "translucency won't change until you restart the engine"
3076
3077 if (general_translucency)
3078 R_InitTranMap(0);
3079}
3080
3081void M_FullScreen(void) // To (un)set fullscreen video after menu changes
3082{
3083 I_UpdateVideoMode();
3084 V_SetPalette(0);
3085}
3086
3087void M_ChangeDemoSmoothTurns(void)
3088{
3089 if (demo_smoothturns)
3090 gen_settings2[12].m_flags &= ~(S_SKIP|S_SELECT);
3091 else
3092 gen_settings2[12].m_flags |= (S_SKIP|S_SELECT);
3093
3094 R_SmoothPlaying_Reset(NULL);
3095}
3096
3097// Setting up for the General screen. Turn on flags, set pointers,
3098// locate the first item on the screen where the cursor is allowed to
3099// land.
3100
3101void M_General(int choice)
3102{
3103 M_SetupNextMenu(&GeneralDef);
3104
3105 setup_active = true;
3106 setup_screen = ss_gen;
3107 set_general_active = true;
3108 setup_select = false;
3109 default_verify = false;
3110 setup_gather = false;
3111 mult_screens_index = 0;
3112 current_setup_menu = gen_settings[0];
3113 set_menu_itemon = 0;
3114 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3115 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3116}
3117
3118// The drawing part of the General Setup initialization. Draw the
3119// background, title, instruction line, and items.
3120
3121void M_DrawGeneral(void)
3122{
3123 inhelpscreens = true;
3124
3125 M_DrawBackground("FLOOR4_6", 0); // Draw background
3126 // proff/nicolas 09/20/98 -- changed for hi-res
3127 V_DrawNamePatch(114, 2, 0, "M_GENERL", CR_DEFAULT, VPT_STRETCH);
3128 M_DrawInstructions();
3129 M_DrawScreenItems(current_setup_menu);
3130
3131 // If the Reset Button has been selected, an "Are you sure?" message
3132 // is overlayed across everything else.
3133
3134 if (default_verify)
3135 M_DrawDefVerify();
3136}
3137
3138/////////////////////////////
3139//
3140// The Compatibility table.
3141// killough 10/10/98
3142
3143#define C_X 284
3144#define C_Y 32
3145#define COMP_SPC 12
3146#define C_NEXTPREV 131
3147
3148setup_menu_t comp_settings1[], comp_settings2[], comp_settings3[];
3149
3150setup_menu_t* comp_settings[] =
3151{
3152 comp_settings1,
3153 comp_settings2,
3154 comp_settings3,
3155 NULL
3156};
3157
3158enum
3159{
3160 compat_telefrag,
3161 compat_dropoff,
3162 compat_falloff,
3163 compat_staylift,
3164 compat_doorstuck,
3165 compat_pursuit,
3166 compat_vile,
3167 compat_pain,
3168 compat_skull,
3169 compat_blazing,
3170 compat_doorlight = 0,
3171 compat_god,
3172 compat_infcheat,
3173 compat_zombie,
3174 compat_skymap,
3175 compat_stairs,
3176 compat_floors,
3177 compat_moveblock,
3178 compat_model,
3179 compat_zerotags,
3180 compat_666 = 0,
3181 compat_soul,
3182 compat_maskedanim,
3183};
3184
3185setup_menu_t comp_settings1[] = // Compatibility Settings screen #1
3186{
3187 {"Any monster can telefrag on MAP30", S_YESNO, m_null, C_X,
3188 C_Y + compat_telefrag * COMP_SPC, {"comp_telefrag"}},
3189
3190 {"Some objects never hang over tall ledges", S_YESNO, m_null, C_X,
3191 C_Y + compat_dropoff * COMP_SPC, {"comp_dropoff"}},
3192
3193 {"Objects don't fall under their own weight", S_YESNO, m_null, C_X,
3194 C_Y + compat_falloff * COMP_SPC, {"comp_falloff"}},
3195
3196 {"Monsters randomly walk off of moving lifts", S_YESNO, m_null, C_X,
3197 C_Y + compat_staylift * COMP_SPC, {"comp_staylift"}},
3198
3199 {"Monsters get stuck on doortracks", S_YESNO, m_null, C_X,
3200 C_Y + compat_doorstuck * COMP_SPC, {"comp_doorstuck"}},
3201
3202 {"Monsters don't give up pursuit of targets", S_YESNO, m_null, C_X,
3203 C_Y + compat_pursuit * COMP_SPC, {"comp_pursuit"}},
3204
3205 {"Arch-Vile resurrects invincible ghosts", S_YESNO, m_null, C_X,
3206 C_Y + compat_vile * COMP_SPC, {"comp_vile"}},
3207
3208 {"Pain Elementals limited to 21 lost souls", S_YESNO, m_null, C_X,
3209 C_Y + compat_pain * COMP_SPC, {"comp_pain"}},
3210
3211 {"Lost souls get stuck behind walls", S_YESNO, m_null, C_X,
3212 C_Y + compat_skull * COMP_SPC, {"comp_skull"}},
3213
3214 {"Blazing doors make double closing sounds", S_YESNO, m_null, C_X,
3215 C_Y + compat_blazing * COMP_SPC, {"comp_blazing"}},
3216
3217 // Button for resetting to defaults
3218 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3219
3220 {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings2}},
3221
3222 // Final entry
3223 {0,S_SKIP|S_END,m_null}
3224};
3225
3226setup_menu_t comp_settings2[] = // Compatibility Settings screen #2
3227{
3228 {"Tagged doors don't trigger special lighting", S_YESNO, m_null, C_X,
3229 C_Y + compat_doorlight * COMP_SPC, {"comp_doorlight"}},
3230
3231 {"God mode isn't absolute", S_YESNO, m_null, C_X,
3232 C_Y + compat_god * COMP_SPC, {"comp_god"}},
3233
3234 {"Powerup cheats are not infinite duration", S_YESNO, m_null, C_X,
3235 C_Y + compat_infcheat * COMP_SPC, {"comp_infcheat"}},
3236
3237 {"Zombie players can exit levels", S_YESNO, m_null, C_X,
3238 C_Y + compat_zombie * COMP_SPC, {"comp_zombie"}},
3239
3240 {"Sky is unaffected by invulnerability", S_YESNO, m_null, C_X,
3241 C_Y + compat_skymap * COMP_SPC, {"comp_skymap"}},
3242
3243 {"Use exactly Doom's stairbuilding method", S_YESNO, m_null, C_X,
3244 C_Y + compat_stairs * COMP_SPC, {"comp_stairs"}},
3245
3246 {"Use exactly Doom's floor motion behavior", S_YESNO, m_null, C_X,
3247 C_Y + compat_floors * COMP_SPC, {"comp_floors"}},
3248
3249 {"Use exactly Doom's movement clipping code", S_YESNO, m_null, C_X,
3250 C_Y + compat_moveblock * COMP_SPC, {"comp_moveblock"}},
3251
3252 {"Use exactly Doom's linedef trigger model", S_YESNO, m_null, C_X,
3253 C_Y + compat_model * COMP_SPC, {"comp_model"}},
3254
3255 {"Linedef effects work with sector tag = 0", S_YESNO, m_null, C_X,
3256 C_Y + compat_zerotags * COMP_SPC, {"comp_zerotags"}},
3257
3258 {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings1}},
3259
3260 {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings3}},
3261
3262 // Final entry
3263
3264 {0,S_SKIP|S_END,m_null}
3265};
3266
3267setup_menu_t comp_settings3[] = // Compatibility Settings screen #2
3268{
3269 {"All boss types can trigger tag 666 at ExM8", S_YESNO, m_null, C_X,
3270 C_Y + compat_666 * COMP_SPC, {"comp_666"}},
3271
3272 {"Lost souls don't bounce off flat surfaces", S_YESNO, m_null, C_X,
3273 C_Y + compat_soul * COMP_SPC, {"comp_soul"}},
3274
3275 {"2S middle textures do not animate", S_YESNO, m_null, C_X,
3276 C_Y + compat_maskedanim * COMP_SPC, {"comp_maskedanim"}},
3277
3278 {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings2}},
3279
3280 // Final entry
3281
3282 {0,S_SKIP|S_END,m_null}
3283};
3284
3285// Setting up for the Compatibility screen. Turn on flags, set pointers,
3286// locate the first item on the screen where the cursor is allowed to
3287// land.
3288
3289void M_Compat(int choice)
3290{
3291 M_SetupNextMenu(&CompatDef);
3292
3293 setup_active = true;
3294 setup_screen = ss_comp;
3295 set_general_active = true;
3296 setup_select = false;
3297 default_verify = false;
3298 setup_gather = false;
3299 mult_screens_index = 0;
3300 current_setup_menu = comp_settings[0];
3301 set_menu_itemon = 0;
3302 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3303 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3304}
3305
3306// The drawing part of the Compatibility Setup initialization. Draw the
3307// background, title, instruction line, and items.
3308
3309void M_DrawCompat(void)
3310{
3311 inhelpscreens = true;
3312
3313 M_DrawBackground("FLOOR4_6", 0); // Draw background
3314 V_DrawNamePatch(52,2,0,"M_COMPAT", CR_DEFAULT, VPT_STRETCH);
3315 M_DrawInstructions();
3316 M_DrawScreenItems(current_setup_menu);
3317
3318 // If the Reset Button has been selected, an "Are you sure?" message
3319 // is overlayed across everything else.
3320
3321 if (default_verify)
3322 M_DrawDefVerify();
3323}
3324
3325/////////////////////////////
3326//
3327// The Messages table.
3328
3329#define M_X 230
3330#define M_Y 39
3331
3332// killough 11/98: enumerated
3333
3334enum {
3335 mess_color_play,
3336 mess_timer,
3337 mess_color_chat,
3338 mess_chat_timer,
3339 mess_color_review,
3340 mess_timed,
3341 mess_hud_timer,
3342 mess_lines,
3343 mess_scrollup,
3344 mess_background,
3345};
3346
3347setup_menu_t mess_settings1[];
3348
3349setup_menu_t* mess_settings[] =
3350{
3351 mess_settings1,
3352 NULL
3353};
3354
3355setup_menu_t mess_settings1[] = // Messages screen
3356{
3357 {"Message Color During Play", S_CRITEM, m_null, M_X,
3358 M_Y + mess_color_play*8, {"hudcolor_mesg"}},
3359
3360#if 0
3361 {"Message Duration During Play (ms)", S_NUM, m_null, M_X,
3362 M_Y + mess_timer*8, {"message_timer"}},
3363#endif
3364
3365 {"Chat Message Color", S_CRITEM, m_null, M_X,
3366 M_Y + mess_color_chat*8, {"hudcolor_chat"}},
3367
3368#if 0
3369 {"Chat Message Duration (ms)", S_NUM, m_null, M_X,
3370 M_Y + mess_chat_timer*8, {"chat_msg_timer"}},
3371#endif
3372
3373 {"Message Review Color", S_CRITEM, m_null, M_X,
3374 M_Y + mess_color_review*8, {"hudcolor_list"}},
3375
3376#if 0
3377 {"Message Listing Review is Temporary", S_YESNO, m_null, M_X,
3378 M_Y + mess_timed*8, {"hud_msg_timed"}},
3379
3380 {"Message Review Duration (ms)", S_NUM, m_null, M_X,
3381 M_Y + mess_hud_timer*8, {"hud_msg_timer"}},
3382#endif
3383
3384 {"Number of Review Message Lines", S_NUM, m_null, M_X,
3385 M_Y + mess_lines*8, {"hud_msg_lines"}},
3386
3387#if 0
3388 {"Message Listing Scrolls Upwards", S_YESNO, m_null, M_X,
3389 M_Y + mess_scrollup*8, {"hud_msg_scrollup"}},
3390#endif
3391
3392 {"Message Background", S_YESNO, m_null, M_X,
3393 M_Y + mess_background*8, {"hud_list_bgon"}},
3394
3395 // Button for resetting to defaults
3396 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3397
3398 // Final entry
3399
3400 {0,S_SKIP|S_END,m_null}
3401};
3402
3403
3404// Setting up for the Messages screen. Turn on flags, set pointers,
3405// locate the first item on the screen where the cursor is allowed to
3406// land.
3407
3408void M_Messages(int choice)
3409{
3410 M_SetupNextMenu(&MessageDef);
3411
3412 setup_active = true;
3413 setup_screen = ss_mess;
3414 set_mess_active = true;
3415 setup_select = false;
3416 default_verify = false;
3417 setup_gather = false;
3418 mult_screens_index = 0;
3419 current_setup_menu = mess_settings[0];
3420 set_menu_itemon = 0;
3421 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3422 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3423}
3424
3425
3426// The drawing part of the Messages Setup initialization. Draw the
3427// background, title, instruction line, and items.
3428
3429void M_DrawMessages(void)
3430
3431{
3432 inhelpscreens = true;
3433 M_DrawBackground("FLOOR4_6", 0); // Draw background
3434 // CPhipps - patch drawing updated
3435 V_DrawNamePatch(103, 2, 0, "M_MESS", CR_DEFAULT, VPT_STRETCH);
3436 M_DrawInstructions();
3437 M_DrawScreenItems(current_setup_menu);
3438 if (default_verify)
3439 M_DrawDefVerify();
3440}
3441
3442
3443/////////////////////////////
3444//
3445// The Chat Strings table.
3446
3447#define CS_X 20
3448#define CS_Y (31+8)
3449
3450setup_menu_t chat_settings1[];
3451
3452setup_menu_t* chat_settings[] =
3453{
3454 chat_settings1,
3455 NULL
3456};
3457
3458setup_menu_t chat_settings1[] = // Chat Strings screen
3459{
3460 {"1",S_CHAT,m_null,CS_X,CS_Y+ 1*8, {"chatmacro1"}},
3461 {"2",S_CHAT,m_null,CS_X,CS_Y+ 2*8, {"chatmacro2"}},
3462 {"3",S_CHAT,m_null,CS_X,CS_Y+ 3*8, {"chatmacro3"}},
3463 {"4",S_CHAT,m_null,CS_X,CS_Y+ 4*8, {"chatmacro4"}},
3464 {"5",S_CHAT,m_null,CS_X,CS_Y+ 5*8, {"chatmacro5"}},
3465 {"6",S_CHAT,m_null,CS_X,CS_Y+ 6*8, {"chatmacro6"}},
3466 {"7",S_CHAT,m_null,CS_X,CS_Y+ 7*8, {"chatmacro7"}},
3467 {"8",S_CHAT,m_null,CS_X,CS_Y+ 8*8, {"chatmacro8"}},
3468 {"9",S_CHAT,m_null,CS_X,CS_Y+ 9*8, {"chatmacro9"}},
3469 {"0",S_CHAT,m_null,CS_X,CS_Y+10*8, {"chatmacro0"}},
3470
3471 // Button for resetting to defaults
3472 {0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
3473
3474 // Final entry
3475 {0,S_SKIP|S_END,m_null}
3476
3477};
3478
3479// Setting up for the Chat Strings screen. Turn on flags, set pointers,
3480// locate the first item on the screen where the cursor is allowed to
3481// land.
3482
3483void M_ChatStrings(int choice)
3484{
3485 M_SetupNextMenu(&ChatStrDef);
3486 setup_active = true;
3487 setup_screen = ss_chat;
3488 set_chat_active = true;
3489 setup_select = false;
3490 default_verify = false;
3491 setup_gather = false;
3492 mult_screens_index = 0;
3493 current_setup_menu = chat_settings[0];
3494 set_menu_itemon = 0;
3495 while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
3496 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
3497}
3498
3499// The drawing part of the Chat Strings Setup initialization. Draw the
3500// background, title, instruction line, and items.
3501
3502void M_DrawChatStrings(void)
3503
3504{
3505 inhelpscreens = true;
3506 M_DrawBackground("FLOOR4_6", 0); // Draw background
3507 // CPhipps - patch drawing updated
3508 V_DrawNamePatch(83, 2, 0, "M_CHAT", CR_DEFAULT, VPT_STRETCH);
3509 M_DrawInstructions();
3510 M_DrawScreenItems(current_setup_menu);
3511
3512 // If the Reset Button has been selected, an "Are you sure?" message
3513 // is overlayed across everything else.
3514
3515 if (default_verify)
3516 M_DrawDefVerify();
3517}
3518
3519/////////////////////////////
3520//
3521// General routines used by the Setup screens.
3522//
3523
3524static boolean shiftdown = false; // phares 4/10/98: SHIFT key down or not
3525
3526// phares 4/17/98:
3527// M_SelectDone() gets called when you have finished entering your
3528// Setup Menu item change.
3529
3530static void M_SelectDone(setup_menu_t* ptr)
3531{
3532 ptr->m_flags &= ~S_SELECT;
3533 ptr->m_flags |= S_HILITE;
3534 S_StartSound(NULL,sfx_itemup);
3535 setup_select = false;
3536 colorbox_active = false;
3537 if (print_warning_about_changes) // killough 8/15/98
3538 print_warning_about_changes--;
3539}
3540
3541// phares 4/21/98:
3542// Array of setup screens used by M_ResetDefaults()
3543
3544static setup_menu_t **setup_screens[] =
3545{
3546 keys_settings,
3547 weap_settings,
3548 stat_settings,
3549 auto_settings,
3550 enem_settings,
3551 mess_settings,
3552 chat_settings,
3553 gen_settings, // killough 10/98
3554 comp_settings,
3555};
3556
3557// phares 4/19/98:
3558// M_ResetDefaults() resets all values for a setup screen to default values
3559//
3560// killough 10/98: rewritten to fix bugs and warn about pending changes
3561
3562static void M_ResetDefaults(void)
3563{
3564 int i; //e6y
3565
3566 default_t *dp;
3567 int warn = 0;
3568
3569 // Look through the defaults table and reset every variable that
3570 // belongs to the group we're interested in.
3571 //
3572 // killough: However, only reset variables whose field in the
3573 // current setup screen is the same as in the defaults table.
3574 // i.e. only reset variables really in the current setup screen.
3575
3576 // e6y
3577 // Fixed crash while trying to read data past array end
3578 // All previous versions of prboom worked only by a lucky accident
3579 // old code: for (dp = defaults; dp->name; dp++)
3580 for (i = 0; i < numdefaults ; i++)
3581 {
3582 dp = &defaults[i];
3583
3584 if (dp->setupscreen == setup_screen)
3585 {
3586 setup_menu_t **l, *p;
3587 for (l = setup_screens[setup_screen-1]; *l; l++)
3588 for (p = *l; !(p->m_flags & S_END); p++)
3589 if (p->m_flags & S_HASDEFPTR ? p->var.def == dp :
3590 p->var.m_key == dp->location.pi ||
3591 p->m_mouse == dp->location.pi ||
3592 p->m_joy == dp->location.pi)
3593 {
3594 if (IS_STRING(*dp))
3595 free((char*)*dp->location.ppsz),
3596 *dp->location.ppsz = strdup(dp->defaultvalue.psz);
3597 else
3598 *dp->location.pi = dp->defaultvalue.i;
3599
3600#if 0
3601 if (p->m_flags & (S_LEVWARN | S_PRGWARN))
3602 warn |= p->m_flags & (S_LEVWARN | S_PRGWARN);
3603 else
3604 if (dp->current)
3605 if (allow_changes())
3606 *dp->current = *dp->location.pi;
3607 else
3608 warn |= S_LEVWARN;
3609#endif
3610 if (p->action)
3611 p->action();
3612
3613 goto end;
3614 }
3615 end:;
3616 }
3617 }
3618
3619 if (warn)
3620 warn_about_changes(warn);
3621}
3622
3623//
3624// M_InitDefaults()
3625//
3626// killough 11/98:
3627//
3628// This function converts all setup menu entries consisting of cfg
3629// variable names, into pointers to the corresponding default[]
3630// array entry. var.name becomes converted to var.def.
3631//
3632
3633static void M_InitDefaults(void)
3634{
3635 setup_menu_t *const *p, *t;
3636 default_t *dp;
3637 int i;
3638 for (i = 0; i < ss_max-1; i++)
3639 for (p = setup_screens[i]; *p; p++)
3640 for (t = *p; !(t->m_flags & S_END); t++)
3641 if (t->m_flags & S_HASDEFPTR) {
3642 if (!(dp = M_LookupDefault(t->var.name)))
3643 I_Error("M_InitDefaults: Couldn't find config variable %s", t->var.name);
3644 else
3645 (t->var.def = dp)->setup_menu = t;
3646 }
3647}
3648
3649//
3650// End of Setup Screens.
3651//
3652/////////////////////////////////////////////////////////////////////////////
3653
3654/////////////////////////////////////////////////////////////////////////////
3655//
3656// Start of Extended HELP screens // phares 3/30/98
3657//
3658// The wad designer can define a set of extended HELP screens for their own
3659// information display. These screens should be 320x200 graphic lumps
3660// defined in a separate wad. They should be named "HELP01" through "HELP99".
3661// "HELP01" is shown after the regular BOOM Dynamic HELP screen, and ENTER
3662// and BACKSPACE keys move the player through the HELP set.
3663//
3664// Rather than define a set of menu definitions for each of the possible
3665// HELP screens, one definition is used, and is altered on the fly
3666// depending on what HELPnn lumps the game finds.
3667
3668// phares 3/30/98:
3669// Extended Help Screen variables
3670
3671int extended_help_count; // number of user-defined help screens found
3672int extended_help_index; // index of current extended help screen
3673
3674menuitem_t ExtHelpMenu[] =
3675{
3676 {1,"",M_ExtHelpNextScreen,0}
3677};
3678
3679menu_t ExtHelpDef =
3680{
3681 1, // # of menu items
3682 &ReadDef1, // previous menu
3683 ExtHelpMenu, // menuitem_t ->
3684 M_DrawExtHelp, // drawing routine ->
3685 330,181, // x,y
3686 0 // lastOn
3687};
3688
3689// M_ExtHelpNextScreen establishes the number of the next HELP screen in
3690// the series.
3691
3692void M_ExtHelpNextScreen(int choice)
3693{
3694 choice = 0;
3695 if (++extended_help_index > extended_help_count)
3696 {
3697
3698 // when finished with extended help screens, return to Main Menu
3699
3700 extended_help_index = 1;
3701 M_SetupNextMenu(&MainDef);
3702 }
3703}
3704
3705// phares 3/30/98:
3706// Routine to look for HELPnn screens and create a menu
3707// definition structure that defines extended help screens.
3708
3709void M_InitExtendedHelp(void)
3710
3711{
3712 int index,i;
3713 char namebfr[] = { "HELPnn"} ;
3714
3715 extended_help_count = 0;
3716 for (index = 1 ; index < 100 ; index++) {
3717 namebfr[4] = index/10 + 0x30;
3718 namebfr[5] = index%10 + 0x30;
3719 i = W_CheckNumForName(namebfr);
3720 if (i == -1) {
3721 if (extended_help_count) {
3722 if (gamemode == commercial) {
3723 ExtHelpDef.prevMenu = &ReadDef1; /* previous menu */
3724 ReadMenu1[0].routine = M_ExtHelp;
3725 } else {
3726 ExtHelpDef.prevMenu = &ReadDef2; /* previous menu */
3727 ReadMenu2[0].routine = M_ExtHelp;
3728 }
3729 }
3730 return;
3731 }
3732 extended_help_count++;
3733 }
3734
3735}
3736
3737// Initialization for the extended HELP screens.
3738
3739void M_ExtHelp(int choice)
3740{
3741 choice = 0;
3742 extended_help_index = 1; // Start with first extended help screen
3743 M_SetupNextMenu(&ExtHelpDef);
3744}
3745
3746// Initialize the drawing part of the extended HELP screens.
3747
3748void M_DrawExtHelp(void)
3749{
3750 char namebfr[10] = { "HELPnn" }; // CPhipps - make it local & writable
3751
3752 inhelpscreens = true; // killough 5/1/98
3753 namebfr[4] = extended_help_index/10 + 0x30;
3754 namebfr[5] = extended_help_index%10 + 0x30;
3755 // CPhipps - patch drawing updated
3756 V_DrawNamePatch(0, 0, 0, namebfr, CR_DEFAULT, VPT_STRETCH);
3757}
3758
3759//
3760// End of Extended HELP screens // phares 3/30/98
3761//
3762////////////////////////////////////////////////////////////////////////////
3763
3764////////////////////////////////////////////////////////////////////////////
3765//
3766// Dynamic HELP screen // phares 3/2/98
3767//
3768// Rather than providing the static HELP screens from DOOM and its versions,
3769// BOOM provides the player with a dynamic HELP screen that displays the
3770// current settings of major key bindings.
3771//
3772// The Dynamic HELP screen is defined in a manner similar to that used for
3773// the Setup Screens above.
3774//
3775// M_GetKeyString finds the correct string to represent the key binding
3776// for the current item being drawn.
3777
3778int M_GetKeyString(int c,int offset)
3779{
3780 const char* s;
3781
3782 if (c >= 33 && c <= 126) {
3783
3784 // The '=', ',', and '.' keys originally meant the shifted
3785 // versions of those keys, but w/o having to shift them in
3786 // the game. Any actions that are mapped to these keys will
3787 // still mean their shifted versions. Could be changed later
3788 // if someone can come up with a better way to deal with them.
3789
3790 if (c == '=') // probably means the '+' key?
3791 c = '+';
3792 else if (c == ',') // probably means the '<' key?
3793 c = '<';
3794 else if (c == '.') // probably means the '>' key?
3795 c = '>';
3796 menu_buffer[offset++] = c; // Just insert the ascii key
3797 menu_buffer[offset] = 0;
3798
3799 } else {
3800
3801 // Retrieve 4-letter (max) string representing the key
3802
3803 // cph - Keypad keys, general code reorganisation to
3804 // make this smaller and neater.
3805 if ((0x100 <= c) && (c < 0x200)) {
3806 if (c == KEYD_KEYPADENTER)
3807 s = "PADE";
3808 else {
3809 strcpy(&menu_buffer[offset], "PAD");
3810 offset+=4;
3811 menu_buffer[offset-1] = c & 0xff;
3812 menu_buffer[offset] = 0;
3813 }
3814 } else if ((KEYD_F1 <= c) && (c < KEYD_F10)) {
3815 menu_buffer[offset++] = 'F';
3816 menu_buffer[offset++] = '1' + c - KEYD_F1;
3817 menu_buffer[offset] = 0;
3818 } else {
3819 switch(c) {
3820 case KEYD_TAB: s = "TAB"; break;
3821 case KEYD_ENTER: s = "ENTR"; break;
3822 case KEYD_ESCAPE: s = "ESC"; break;
3823 case KEYD_SPACEBAR: s = "SPAC"; break;
3824 case KEYD_BACKSPACE: s = "BACK"; break;
3825 case KEYD_RCTRL: s = "CTRL"; break;
3826 case KEYD_LEFTARROW: s = "LARR"; break;
3827 case KEYD_UPARROW: s = "UARR"; break;
3828 case KEYD_RIGHTARROW: s = "RARR"; break;
3829 case KEYD_DOWNARROW: s = "DARR"; break;
3830 case KEYD_RSHIFT: s = "SHFT"; break;
3831 case KEYD_RALT: s = "ALT"; break;
3832 case KEYD_CAPSLOCK: s = "CAPS"; break;
3833 case KEYD_SCROLLLOCK: s = "SCRL"; break;
3834 case KEYD_HOME: s = "HOME"; break;
3835 case KEYD_PAGEUP: s = "PGUP"; break;
3836 case KEYD_END: s = "END"; break;
3837 case KEYD_PAGEDOWN: s = "PGDN"; break;
3838 case KEYD_INSERT: s = "INST"; break;
3839 case KEYD_DEL: s = "DEL"; break;
3840 case KEYD_F10: s = "F10"; break;
3841 case KEYD_F11: s = "F11"; break;
3842 case KEYD_F12: s = "F12"; break;
3843 case KEYD_PAUSE: s = "PAUS"; break;
3844 default: s = "JUNK"; break;
3845 }
3846
3847 if (s) { // cph - Slight code change
3848 strcpy(&menu_buffer[offset],s); // string to display
3849 offset += strlen(s);
3850 }
3851 }
3852 }
3853 return offset;
3854}
3855
3856//
3857// The Dynamic HELP screen table.
3858
3859#define KT_X1 283
3860#define KT_X2 172
3861#define KT_X3 87
3862
3863#define KT_Y1 2
3864#define KT_Y2 118
3865#define KT_Y3 102
3866
3867setup_menu_t helpstrings[] = // HELP screen strings
3868{
3869 {"SCREEN" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y1},
3870 {"HELP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 1*8,{&key_help}},
3871 {"MENU" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 2*8,{&key_escape}},
3872 {"SETUP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 3*8,{&key_setup}},
3873 {"PAUSE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 4*8,{&key_pause}},
3874 {"AUTOMAP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 5*8,{&key_map}},
3875 {"SOUND VOLUME",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 6*8,{&key_soundvolume}},
3876 {"HUD" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 7*8,{&key_hud}},
3877 {"MESSAGES" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 8*8,{&key_messages}},
3878 {"GAMMA FIX" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 9*8,{&key_gamma}},
3879 {"SPY" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+10*8,{&key_spy}},
3880 {"LARGER VIEW" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+11*8,{&key_zoomin}},
3881 {"SMALLER VIEW",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+12*8,{&key_zoomout}},
3882 {"SCREENSHOT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+13*8,{&key_screenshot}},
3883
3884 {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y2},
3885 {"FOLLOW MODE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 1*8,{&key_map_follow}},
3886 {"ZOOM IN" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 2*8,{&key_map_zoomin}},
3887 {"ZOOM OUT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 3*8,{&key_map_zoomout}},
3888 {"MARK PLACE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 4*8,{&key_map_mark}},
3889 {"CLEAR MARKS" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 5*8,{&key_map_clear}},
3890 {"FULL/ZOOM" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 6*8,{&key_map_gobig}},
3891 {"GRID" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 7*8,{&key_map_grid}},
3892
3893 {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y1},
3894 {"FIST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 1*8,{&key_weapon1}},
3895 {"PISTOL" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 2*8,{&key_weapon2}},
3896 {"SHOTGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 3*8,{&key_weapon3}},
3897 {"CHAINGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 4*8,{&key_weapon4}},
3898 {"ROCKET" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 5*8,{&key_weapon5}},
3899 {"PLASMA" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 6*8,{&key_weapon6}},
3900 {"BFG 9000" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 7*8,{&key_weapon7}},
3901 {"CHAINSAW" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 8*8,{&key_weapon8}},
3902 {"SSG" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 9*8,{&key_weapon9}},
3903 {"BEST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+10*8,{&key_weapontoggle}},
3904 {"FIRE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+11*8,{&key_fire},&mousebfire,&joybfire},
3905
3906 {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y3},
3907 {"FORWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 1*8,{&key_up},&mousebforward},
3908 {"BACKWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 2*8,{&key_down}},
3909 {"TURN LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 3*8,{&key_left}},
3910 {"TURN RIGHT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 4*8,{&key_right}},
3911 {"RUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 5*8,{&key_speed},0,&joybspeed},
3912 {"STRAFE LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 6*8,{&key_strafeleft}},
3913 {"STRAFE RIGHT",S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 7*8,{&key_straferight}},
3914 {"STRAFE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
3915 {"AUTORUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 9*8,{&key_autorun}},
3916 {"180 TURN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+10*8,{&key_reverse}},
3917 {"USE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+11*8,{&key_use},&mousebforward,&joybuse},
3918
3919 {"GAME" ,S_SKIP|S_TITLE,m_null,KT_X2,KT_Y1},
3920 {"SAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 1*8,{&key_savegame}},
3921 {"LOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 2*8,{&key_loadgame}},
3922 {"QUICKSAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 3*8,{&key_quicksave}},
3923 {"END GAME" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 4*8,{&key_endgame}},
3924 {"QUICKLOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 5*8,{&key_quickload}},
3925 {"QUIT" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 6*8,{&key_quit}},
3926
3927 // Final entry
3928
3929 {0,S_SKIP|S_END,m_null}
3930};
3931
3932#define SPACEWIDTH 4
3933
3934/* cph 2006/08/06
3935 * M_DrawString() is the old M_DrawMenuString, except that it is not tied to
3936 * menu_buffer - no reason to force all the callers to write into one array! */
3937
3938static void M_DrawString(int cx, int cy, int color, const char* ch)
3939{
3940 int w;
3941 int c;
3942
3943 while (*ch) {
3944 c = *ch++; // get next char
3945 c = toupper(c) - HU_FONTSTART;
3946 if (c < 0 || c> HU_FONTSIZE)
3947 {
3948 cx += SPACEWIDTH; // space
3949 continue;
3950 }
3951 w = hu_font[c].width;
3952 if (cx + w > 320)
3953 break;
3954
3955 // V_DrawpatchTranslated() will draw the string in the
3956 // desired color, colrngs[color]
3957
3958 // CPhipps - patch drawing updated
3959 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, color, VPT_STRETCH | VPT_TRANS);
3960 // The screen is cramped, so trim one unit from each
3961 // character so they butt up against each other.
3962 cx += w - 1;
3963 }
3964}
3965
3966// M_DrawMenuString() draws the string in menu_buffer[]
3967
3968static void M_DrawMenuString(int cx, int cy, int color)
3969{
3970 M_DrawString(cx, cy, color, menu_buffer);
3971}
3972
3973// M_GetPixelWidth() returns the number of pixels in the width of
3974// the string, NOT the number of chars in the string.
3975
3976static int M_GetPixelWidth(const char* ch)
3977{
3978 int len = 0;
3979 int c;
3980
3981 while (*ch) {
3982 c = *ch++; // pick up next char
3983 c = toupper(c) - HU_FONTSTART;
3984 if (c < 0 || c > HU_FONTSIZE)
3985 {
3986 len += SPACEWIDTH; // space
3987 continue;
3988 }
3989 len += hu_font[c].width;
3990 len--; // adjust so everything fits
3991 }
3992 len++; // replace what you took away on the last char only
3993 return len;
3994}
3995
3996static void M_DrawStringCentered(int cx, int cy, int color, const char* ch)
3997{
3998 M_DrawString(cx - M_GetPixelWidth(ch)/2, cy, color, ch);
3999}
4000
4001//
4002// M_DrawHelp
4003//
4004// This displays the help screen
4005
4006void M_DrawHelp (void)
4007{
4008 inhelpscreens = true; // killough 10/98
4009 M_DrawBackground("FLOOR4_6", 0);
4010
4011 M_DrawScreenItems(helpstrings);
4012}
4013
4014//
4015// End of Dynamic HELP screen // phares 3/2/98
4016//
4017////////////////////////////////////////////////////////////////////////////
4018
4019enum {
4020 prog,
4021 prog_stub,
4022 prog_stub1,
4023 prog_stub2,
4024 adcr
4025};
4026
4027enum {
4028 cr_prog=0,
4029 cr_adcr=2,
4030};
4031
4032#define CR_S 9
4033#define CR_X 20
4034#define CR_X2 50
4035#define CR_Y 32
4036#define CR_SH 9
4037
4038setup_menu_t cred_settings[]={
4039
4040 {"Programmers",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*prog + CR_SH*cr_prog},
4041 {"Florian 'Proff' Schulze",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+1) + CR_SH*cr_prog},
4042 {"Colin Phipps",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+2) + CR_SH*cr_prog},
4043 {"Neil Stevens",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+3) + CR_SH*cr_prog},
4044 {"Andrey Budko",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+4) + CR_SH*cr_prog},
4045
4046 {"Additional Credit To",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*adcr + CR_SH*cr_adcr},
4047 {"id Software for DOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+1)+CR_SH*cr_adcr},
4048 {"TeamTNT for BOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+2)+CR_SH*cr_adcr},
4049 {"Lee Killough for MBF",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+3)+CR_SH*cr_adcr},
4050 {"The DOSDoom-Team for DOSDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+4)+CR_SH*cr_adcr},
4051 {"Randy Heit for ZDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+5)+CR_SH*cr_adcr},
4052 {"Michael 'Kodak' Ryssen for DOOMGL",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+6)+CR_SH*cr_adcr},
4053 {"Jess Haas for lSDLDoom",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+7) + CR_SH*cr_adcr},
4054 {"all others who helped (see AUTHORS file)",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+8)+CR_SH*cr_adcr},
4055
4056 {0,S_SKIP|S_END,m_null}
4057};
4058
4059void M_DrawCredits(void) // killough 10/98: credit screen
4060{
4061 inhelpscreens = true;
4062 M_DrawBackground(gamemode==shareware ? "CEIL5_1" : "MFLR8_4", 0);
4063 V_DrawNamePatch(115,9,0, "PRBOOM",CR_GOLD, VPT_TRANS | VPT_STRETCH);
4064 M_DrawScreenItems(cred_settings);
4065}
4066
4067static int M_IndexInChoices(const char *str, const char **choices) {
4068 int i = 0;
4069
4070 while (*choices != NULL) {
4071 if (!strcmp(str, *choices))
4072 return i;
4073 i++;
4074 choices++;
4075 }
4076 return 0;
4077}
4078
4079/////////////////////////////////////////////////////////////////////////////
4080//
4081// M_Responder
4082//
4083// Examines incoming keystrokes and button pushes and determines some
4084// action based on the state of the system.
4085//
4086
4087boolean M_Responder (event_t* ev) {
4088 int ch;
4089 int i;
4090 static int joywait = 0;
4091 static int mousewait = 0;
4092 static int mousey = 0;
4093 static int lasty = 0;
4094 static int mousex = 0;
4095 static int lastx = 0;
4096
4097 ch = -1; // will be changed to a legit char if we're going to use it here
4098
4099 // Process joystick input
4100
4101 if (ev->type == ev_joystick && joywait < I_GetTime()) {
4102 if (ev->data3 == -1)
4103 {
4104 ch = key_menu_up; // phares 3/7/98
4105 joywait = I_GetTime() + 5;
4106 }
4107 else if (ev->data3 == 1)
4108 {
4109 ch = key_menu_down; // phares 3/7/98
4110 joywait = I_GetTime() + 5;
4111 }
4112
4113 if (ev->data2 == -1)
4114 {
4115 ch = key_menu_left; // phares 3/7/98
4116 joywait = I_GetTime() + 2;
4117 }
4118 else if (ev->data2 == 1)
4119 {
4120 ch = key_menu_right; // phares 3/7/98
4121 joywait = I_GetTime() + 2;
4122 }
4123
4124 if (ev->data1&1)
4125 {
4126 ch = key_menu_enter; // phares 3/7/98
4127 joywait = I_GetTime() + 5;
4128 }
4129
4130 if (ev->data1&2)
4131 {
4132 ch = key_menu_backspace; // phares 3/7/98
4133 joywait = I_GetTime() + 5;
4134 }
4135
4136 // phares 4/4/98:
4137 // Handle joystick buttons 3 and 4, and allow them to pass down
4138 // to where key binding can eat them.
4139
4140 if (setup_active && set_keybnd_active) {
4141 if (ev->data1&4) {
4142 ch = 0; // meaningless, just to get you past the check for -1
4143 joywait = I_GetTime() + 5;
4144 }
4145 if (ev->data1&8) {
4146 ch = 0; // meaningless, just to get you past the check for -1
4147 joywait = I_GetTime() + 5;
4148 }
4149 }
4150
4151 } else {
4152 // Mouse input processing removed
4153
4154 // Process keyboard input
4155
4156 if (ev->type == ev_keydown)
4157 {
4158 ch = ev->data1; // phares 4/11/98:
4159 if (ch == KEYD_RSHIFT) // For chat string processing, need
4160 shiftdown = true; // to know when shift key is up or
4161 } // down so you can get at the !,#,
4162 else if (ev->type == ev_keyup) // etc. keys. Keydowns are allowed
4163 if (ev->data1 == KEYD_RSHIFT) // past this point, but keyups aren't
4164 shiftdown = false; // so we need to note the difference
4165 } // here using the 'shiftdown' boolean.
4166
4167 if (ch == -1)
4168 return false; // we can't use the event here
4169
4170 // Save Game string input
4171
4172 if (saveStringEnter) {
4173 if (ch == key_menu_backspace) // phares 3/7/98
4174 {
4175 if (saveCharIndex > 0)
4176 {
4177 saveCharIndex--;
4178 savegamestrings[saveSlot][saveCharIndex] = 0;
4179 }
4180 }
4181
4182 else if (ch == key_menu_escape) // phares 3/7/98
4183 {
4184 saveStringEnter = 0;
4185 strcpy(&savegamestrings[saveSlot][0],saveOldString);
4186 }
4187
4188 else if (ch == key_menu_enter) // phares 3/7/98
4189 {
4190 saveStringEnter = 0;
4191 if (savegamestrings[saveSlot][0])
4192 M_DoSave(saveSlot);
4193 }
4194
4195 else
4196 {
4197 ch = toupper(ch);
4198 if (ch >= 32 && ch <= 127 &&
4199 saveCharIndex < SAVESTRINGSIZE-1 &&
4200 M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8)
4201 {
4202 savegamestrings[saveSlot][saveCharIndex++] = ch;
4203 savegamestrings[saveSlot][saveCharIndex] = 0;
4204 }
4205 }
4206 return true;
4207 }
4208
4209 // Take care of any messages that need input
4210
4211 if (messageToPrint) {
4212 if (messageNeedsInput == true &&
4213 !(ch == ' ' || ch == 'n' || ch == 'y' || ch == key_escape)) // phares
4214 return false;
4215
4216 menuactive = messageLastMenuActive;
4217 messageToPrint = 0;
4218 if (messageRoutine)
4219 messageRoutine(ch);
4220
4221 menuactive = false;
4222 S_StartSound(NULL,sfx_swtchx);
4223 return true;
4224 }
4225
4226 /* killough 2/22/98: add support for screenshot key:
4227 * cph 2001/02/04: no need for this to be a gameaction, just do it
4228 */
4229 if (ch == key_screenshot)
4230 {
4231 M_ScreenShot ();
4232 // Don't eat the keypress in this case. See sf bug #1843280.
4233 }
4234
4235 // If there is no active menu displayed...
4236
4237 if (!menuactive) { // phares
4238 if (ch == key_autorun) // Autorun // V
4239 {
4240 autorun = !autorun;
4241 return true;
4242 }
4243
4244 if (ch == key_help) // Help key
4245 {
4246 M_StartControlPanel ();
4247
4248 currentMenu = &HelpDef; // killough 10/98: new help screen
4249
4250 itemOn = 0;
4251 S_StartSound(NULL,sfx_swtchn);
4252 return true;
4253 }
4254
4255 if (ch == key_savegame) // Save Game
4256 {
4257 M_StartControlPanel();
4258 S_StartSound(NULL,sfx_swtchn);
4259 M_SaveGame(0);
4260 return true;
4261 }
4262
4263 if (ch == key_loadgame) // Load Game
4264 {
4265 M_StartControlPanel();
4266 S_StartSound(NULL,sfx_swtchn);
4267 M_LoadGame(0);
4268 return true;
4269 }
4270
4271 if (ch == key_soundvolume) // Sound Volume
4272 {
4273 M_StartControlPanel ();
4274 currentMenu = &SoundDef;
4275 itemOn = sfx_vol;
4276 S_StartSound(NULL,sfx_swtchn);
4277 return true;
4278 }
4279
4280 if (ch == key_quicksave) // Quicksave
4281 {
4282 S_StartSound(NULL,sfx_swtchn);
4283 M_QuickSave();
4284 return true;
4285 }
4286
4287 if (ch == key_endgame) // End game
4288 {
4289 S_StartSound(NULL,sfx_swtchn);
4290 M_EndGame(0);
4291 return true;
4292 }
4293
4294 if (ch == key_messages) // Toggle messages
4295 {
4296 M_ChangeMessages(0);
4297 S_StartSound(NULL,sfx_swtchn);
4298 return true;
4299 }
4300
4301 if (ch == key_quickload) // Quickload
4302 {
4303 S_StartSound(NULL,sfx_swtchn);
4304 M_QuickLoad();
4305 return true;
4306 }
4307
4308 if (ch == key_quit) // Quit DOOM
4309 {
4310 S_StartSound(NULL,sfx_swtchn);
4311 M_QuitDOOM(0);
4312 return true;
4313 }
4314
4315 if (ch == key_gamma) // gamma toggle
4316 {
4317 usegamma++;
4318 if (usegamma > 4)
4319 usegamma = 0;
4320 players[consoleplayer].message =
4321 usegamma == 0 ? s_GAMMALVL0 :
4322 usegamma == 1 ? s_GAMMALVL1 :
4323 usegamma == 2 ? s_GAMMALVL2 :
4324 usegamma == 3 ? s_GAMMALVL3 :
4325 s_GAMMALVL4;
4326 V_SetPalette(0);
4327 return true;
4328 }
4329
4330
4331 if (ch == key_zoomout) // zoom out
4332 {
4333 if ((automapmode & am_active) || chat_on)
4334 return false;
4335 M_SizeDisplay(0);
4336 S_StartSound(NULL,sfx_stnmov);
4337 return true;
4338 }
4339
4340 if (ch == key_zoomin) // zoom in
4341 { // jff 2/23/98
4342 if ((automapmode & am_active) || chat_on) // allow
4343 return false; // key_hud==key_zoomin
4344 M_SizeDisplay(1); // ^
4345 S_StartSound(NULL,sfx_stnmov); // |
4346 return true; // phares
4347 }
4348
4349 if (ch == key_hud) // heads-up mode
4350 {
4351 if ((automapmode & am_active) || chat_on) // jff 2/22/98
4352 return false; // HUD mode control
4353 if (screenSize<8) // function on default F5
4354 while (screenSize<8 || !hud_displayed) // make hud visible
4355 M_SizeDisplay(1); // when configuring it
4356 else
4357 {
4358 hud_displayed = 1; //jff 3/3/98 turn hud on
4359 hud_active = (hud_active+1)%3; // cycle hud_active
4360 if (!hud_active) //jff 3/4/98 add distributed
4361 {
4362 hud_distributed = !hud_distributed; // to cycle
4363 HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch
4364 }
4365 }
4366 return true;
4367 }
4368
4369 /* killough 10/98: allow key shortcut into Setup menu */
4370 if (ch == key_setup) {
4371 M_StartControlPanel();
4372 S_StartSound(NULL,sfx_swtchn);
4373 M_SetupNextMenu(&SetupDef);
4374 return true;
4375 }
4376 }
4377 // Pop-up Main menu?
4378
4379 if (!menuactive)
4380 {
4381 if (ch == key_escape) // phares
4382 {
4383 M_StartControlPanel ();
4384 S_StartSound(NULL,sfx_swtchn);
4385 return true;
4386 }
4387 return false;
4388 }
4389
4390 // phares 3/26/98 - 4/11/98:
4391 // Setup screen key processing
4392
4393 if (setup_active) {
4394 setup_menu_t* ptr1= current_setup_menu + set_menu_itemon;
4395 setup_menu_t* ptr2 = NULL;
4396
4397 // phares 4/19/98:
4398 // Catch the response to the 'reset to default?' verification
4399 // screen
4400
4401 if (default_verify)
4402 {
4403 if (toupper(ch) == 'Y') {
4404 M_ResetDefaults();
4405 default_verify = false;
4406 M_SelectDone(ptr1);
4407 }
4408 else if (toupper(ch) == 'N') {
4409 default_verify = false;
4410 M_SelectDone(ptr1);
4411 }
4412 return true;
4413 }
4414
4415 // Common processing for some items
4416
4417 if (setup_select) { // changing an entry
4418 if (ch == key_menu_escape) // Exit key = no change
4419 {
4420 M_SelectDone(ptr1); // phares 4/17/98
4421 setup_gather = false; // finished gathering keys, if any
4422 return true;
4423 }
4424
4425 if (ptr1->m_flags & S_YESNO) // yes or no setting?
4426 {
4427 if (ch == key_menu_enter) {
4428 *ptr1->var.def->location.pi = !*ptr1->var.def->location.pi; // killough 8/15/98
4429
4430 // phares 4/14/98:
4431 // If not in demoplayback, demorecording, or netgame,
4432 // and there's a second variable in var2, set that
4433 // as well
4434
4435 // killough 8/15/98: add warning messages
4436
4437 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4438 warn_about_changes(ptr1->m_flags & // killough 10/98
4439 (S_LEVWARN | S_PRGWARN));
4440 else
4441 M_UpdateCurrent(ptr1->var.def);
4442
4443 if (ptr1->action) // killough 10/98
4444 ptr1->action();
4445 }
4446 M_SelectDone(ptr1); // phares 4/17/98
4447 return true;
4448 }
4449
4450 if (ptr1->m_flags & S_CRITEM)
4451 {
4452 if (ch != key_menu_enter)
4453 {
4454 ch -= 0x30; // out of ascii
4455 if (ch < 0 || ch > 9)
4456 return true; // ignore
4457 *ptr1->var.def->location.pi = ch;
4458 }
4459 if (ptr1->action) // killough 10/98
4460 ptr1->action();
4461 M_SelectDone(ptr1); // phares 4/17/98
4462 return true;
4463 }
4464
4465 if (ptr1->m_flags & S_NUM) // number?
4466 {
4467 if (setup_gather) { // gathering keys for a value?
4468 /* killough 10/98: Allow negatives, and use a more
4469 * friendly input method (e.g. don't clear value early,
4470 * allow backspace, and return to original value if bad
4471 * value is entered).
4472 */
4473 if (ch == key_menu_enter) {
4474 if (gather_count) { // Any input?
4475 int value;
4476
4477 gather_buffer[gather_count] = 0;
4478 value = atoi(gather_buffer); // Integer value
4479
4480 if ((ptr1->var.def->minvalue != UL &&
4481 value < ptr1->var.def->minvalue) ||
4482 (ptr1->var.def->maxvalue != UL &&
4483 value > ptr1->var.def->maxvalue))
4484 warn_about_changes(S_BADVAL);
4485 else {
4486 *ptr1->var.def->location.pi = value;
4487
4488 /* killough 8/9/98: fix numeric vars
4489 * killough 8/15/98: add warning message
4490 */
4491 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4492 warn_about_changes(ptr1->m_flags &
4493 (S_LEVWARN | S_PRGWARN));
4494 else
4495 M_UpdateCurrent(ptr1->var.def);
4496
4497 if (ptr1->action) // killough 10/98
4498 ptr1->action();
4499 }
4500 }
4501 M_SelectDone(ptr1); // phares 4/17/98
4502 setup_gather = false; // finished gathering keys
4503 return true;
4504 }
4505
4506 if (ch == key_menu_backspace && gather_count) {
4507 gather_count--;
4508 return true;
4509 }
4510
4511 if (gather_count >= MAXGATHER)
4512 return true;
4513
4514 if (!isdigit(ch) && ch != '-')
4515 return true; // ignore
4516
4517 /* killough 10/98: character-based numerical input */
4518 gather_buffer[gather_count++] = ch;
4519 }
4520 return true;
4521 }
4522
4523 if (ptr1->m_flags & S_CHOICE) // selection of choices?
4524 {
4525 if (ch == key_menu_left) {
4526 if (ptr1->var.def->type == def_int) {
4527 int value = *ptr1->var.def->location.pi;
4528
4529 value = value - 1;
4530 if ((ptr1->var.def->minvalue != UL &&
4531 value < ptr1->var.def->minvalue))
4532 value = ptr1->var.def->minvalue;
4533 if ((ptr1->var.def->maxvalue != UL &&
4534 value > ptr1->var.def->maxvalue))
4535 value = ptr1->var.def->maxvalue;
4536 if (*ptr1->var.def->location.pi != value)
4537 S_StartSound(NULL,sfx_pstop);
4538 *ptr1->var.def->location.pi = value;
4539 }
4540 if (ptr1->var.def->type == def_str) {
4541 int old_value, value;
4542
4543 old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
4544 ptr1->selectstrings);
4545 value = old_value - 1;
4546 if (value < 0)
4547 value = 0;
4548 if (old_value != value)
4549 S_StartSound(NULL,sfx_pstop);
4550 *ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
4551 }
4552 }
4553 if (ch == key_menu_right) {
4554 if (ptr1->var.def->type == def_int) {
4555 int value = *ptr1->var.def->location.pi;
4556
4557 value = value + 1;
4558 if ((ptr1->var.def->minvalue != UL &&
4559 value < ptr1->var.def->minvalue))
4560 value = ptr1->var.def->minvalue;
4561 if ((ptr1->var.def->maxvalue != UL &&
4562 value > ptr1->var.def->maxvalue))
4563 value = ptr1->var.def->maxvalue;
4564 if (*ptr1->var.def->location.pi != value)
4565 S_StartSound(NULL,sfx_pstop);
4566 *ptr1->var.def->location.pi = value;
4567 }
4568 if (ptr1->var.def->type == def_str) {
4569 int old_value, value;
4570
4571 old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
4572 ptr1->selectstrings);
4573 value = old_value + 1;
4574 if (ptr1->selectstrings[value] == NULL)
4575 value = old_value;
4576 if (old_value != value)
4577 S_StartSound(NULL,sfx_pstop);
4578 *ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
4579 }
4580 }
4581 if (ch == key_menu_enter) {
4582 // phares 4/14/98:
4583 // If not in demoplayback, demorecording, or netgame,
4584 // and there's a second variable in var2, set that
4585 // as well
4586
4587 // killough 8/15/98: add warning messages
4588
4589 if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
4590 warn_about_changes(ptr1->m_flags & // killough 10/98
4591 (S_LEVWARN | S_PRGWARN));
4592 else
4593 M_UpdateCurrent(ptr1->var.def);
4594
4595 if (ptr1->action) // killough 10/98
4596 ptr1->action();
4597 M_SelectDone(ptr1); // phares 4/17/98
4598 }
4599 return true;
4600 }
4601
4602 }
4603
4604 // Key Bindings
4605
4606 if (set_keybnd_active) // on a key binding setup screen
4607 if (setup_select) // incoming key or button gets bound
4608 {
4609 if (ev->type == ev_joystick)
4610 {
4611 int oldbutton,group;
4612 boolean search = true;
4613
4614 if (!ptr1->m_joy)
4615 return true; // not a legal action here (yet)
4616
4617 // see if the button is already bound elsewhere. if so, you
4618 // have to swap bindings so the action where it's currently
4619 // bound doesn't go dead. Since there is more than one
4620 // keybinding screen, you have to search all of them for
4621 // any duplicates. You're only interested in the items
4622 // that belong to the same group as the one you're changing.
4623
4624 oldbutton = *ptr1->m_joy;
4625 group = ptr1->m_group;
4626 if (ev->data1 & 1)
4627 ch = 0;
4628 else if (ev->data1 & 2)
4629 ch = 1;
4630 else if (ev->data1 & 4)
4631 ch = 2;
4632 else if (ev->data1 & 8)
4633 ch = 3;
4634 else
4635 return true;
4636 for (i = 0 ; keys_settings[i] && search ; i++)
4637 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4638 if (ptr2->m_group == group && ptr1 != ptr2)
4639 if (ptr2->m_flags & S_KEY && ptr2->m_joy)
4640 if (*ptr2->m_joy == ch)
4641 {
4642 *ptr2->m_joy = oldbutton;
4643 search = false;
4644 break;
4645 }
4646 *ptr1->m_joy = ch;
4647 }
4648 else if (ev->type == ev_mouse)
4649 {
4650 int i,oldbutton,group;
4651 boolean search = true;
4652
4653 if (!ptr1->m_mouse)
4654 return true; // not a legal action here (yet)
4655
4656 // see if the button is already bound elsewhere. if so, you
4657 // have to swap bindings so the action where it's currently
4658 // bound doesn't go dead. Since there is more than one
4659 // keybinding screen, you have to search all of them for
4660 // any duplicates. You're only interested in the items
4661 // that belong to the same group as the one you're changing.
4662
4663 oldbutton = *ptr1->m_mouse;
4664 group = ptr1->m_group;
4665 if (ev->data1 & 1)
4666 ch = 0;
4667 else if (ev->data1 & 2)
4668 ch = 1;
4669 else if (ev->data1 & 4)
4670 ch = 2;
4671 else
4672 return true;
4673 for (i = 0 ; keys_settings[i] && search ; i++)
4674 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4675 if (ptr2->m_group == group && ptr1 != ptr2)
4676 if (ptr2->m_flags & S_KEY && ptr2->m_mouse)
4677 if (*ptr2->m_mouse == ch)
4678 {
4679 *ptr2->m_mouse = oldbutton;
4680 search = false;
4681 break;
4682 }
4683 *ptr1->m_mouse = ch;
4684 }
4685 else // keyboard key
4686 {
4687 int i,oldkey,group;
4688 boolean search = true;
4689
4690 // see if 'ch' is already bound elsewhere. if so, you have
4691 // to swap bindings so the action where it's currently
4692 // bound doesn't go dead. Since there is more than one
4693 // keybinding screen, you have to search all of them for
4694 // any duplicates. You're only interested in the items
4695 // that belong to the same group as the one you're changing.
4696
4697 // if you find that you're trying to swap with an action
4698 // that has S_KEEP set, you can't bind ch; it's already
4699 // bound to that S_KEEP action, and that action has to
4700 // keep that key.
4701
4702 oldkey = *ptr1->var.m_key;
4703 group = ptr1->m_group;
4704 for (i = 0 ; keys_settings[i] && search ; i++)
4705 for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
4706 if (ptr2->m_flags & (S_KEY|S_KEEP) &&
4707 ptr2->m_group == group &&
4708 ptr1 != ptr2)
4709 if (*ptr2->var.m_key == ch)
4710 {
4711 if (ptr2->m_flags & S_KEEP)
4712 return true; // can't have it!
4713 *ptr2->var.m_key = oldkey;
4714 search = false;
4715 break;
4716 }
4717 *ptr1->var.m_key = ch;
4718 }
4719
4720 M_SelectDone(ptr1); // phares 4/17/98
4721 return true;
4722 }
4723
4724 // Weapons
4725
4726 if (set_weapon_active) // on the weapons setup screen
4727 if (setup_select) // changing an entry
4728 {
4729 if (ch != key_menu_enter)
4730 {
4731 ch -= '0'; // out of ascii
4732 if (ch < 1 || ch > 9)
4733 return true; // ignore
4734
4735 // Plasma and BFG don't exist in shareware
4736 // killough 10/98: allow it anyway, since this
4737 // isn't the game itself, just setting preferences
4738
4739 // see if 'ch' is already assigned elsewhere. if so,
4740 // you have to swap assignments.
4741
4742 // killough 11/98: simplified
4743
4744 for (i = 0; (ptr2 = weap_settings[i]); i++)
4745 for (; !(ptr2->m_flags & S_END); ptr2++)
4746 if (ptr2->m_flags & S_WEAP &&
4747 *ptr2->var.def->location.pi == ch && ptr1 != ptr2)
4748 {
4749 *ptr2->var.def->location.pi = *ptr1->var.def->location.pi;
4750 goto end;
4751 }
4752 end:
4753 *ptr1->var.def->location.pi = ch;
4754 }
4755
4756 M_SelectDone(ptr1); // phares 4/17/98
4757 return true;
4758 }
4759
4760 // Automap
4761
4762 if (set_auto_active) // on the automap setup screen
4763 if (setup_select) // incoming key
4764 {
4765 if (ch == key_menu_down)
4766 {
4767 if (++color_palette_y == 16)
4768 color_palette_y = 0;
4769 S_StartSound(NULL,sfx_itemup);
4770 return true;
4771 }
4772
4773 if (ch == key_menu_up)
4774 {
4775 if (--color_palette_y < 0)
4776 color_palette_y = 15;
4777 S_StartSound(NULL,sfx_itemup);
4778 return true;
4779 }
4780
4781 if (ch == key_menu_left)
4782 {
4783 if (--color_palette_x < 0)
4784 color_palette_x = 15;
4785 S_StartSound(NULL,sfx_itemup);
4786 return true;
4787 }
4788
4789 if (ch == key_menu_right)
4790 {
4791 if (++color_palette_x == 16)
4792 color_palette_x = 0;
4793 S_StartSound(NULL,sfx_itemup);
4794 return true;
4795 }
4796
4797 if (ch == key_menu_enter)
4798 {
4799 *ptr1->var.def->location.pi = color_palette_x + 16*color_palette_y;
4800 M_SelectDone(ptr1); // phares 4/17/98
4801 colorbox_active = false;
4802 return true;
4803 }
4804 }
4805
4806 // killough 10/98: consolidate handling into one place:
4807 if (setup_select &&
4808 set_enemy_active | set_general_active | set_chat_active |
4809 set_mess_active | set_status_active | set_compat_active)
4810 {
4811 if (ptr1->m_flags & S_STRING) // creating/editing a string?
4812 {
4813 if (ch == key_menu_backspace) // backspace and DEL
4814 {
4815 if (chat_string_buffer[chat_index] == 0)
4816 {
4817 if (chat_index > 0)
4818 chat_string_buffer[--chat_index] = 0;
4819 }
4820 // shift the remainder of the text one char left
4821 else
4822 strcpy(&chat_string_buffer[chat_index],
4823 &chat_string_buffer[chat_index+1]);
4824 }
4825 else if (ch == key_menu_left) // move cursor left
4826 {
4827 if (chat_index > 0)
4828 chat_index--;
4829 }
4830 else if (ch == key_menu_right) // move cursor right
4831 {
4832 if (chat_string_buffer[chat_index] != 0)
4833 chat_index++;
4834 }
4835 else if ((ch == key_menu_enter) ||
4836 (ch == key_menu_escape))
4837 {
4838 *ptr1->var.def->location.ppsz = chat_string_buffer;
4839 M_SelectDone(ptr1); // phares 4/17/98
4840 }
4841
4842 // Adding a char to the text. Has to be a printable
4843 // char, and you can't overrun the buffer. If the
4844 // chat string gets larger than what the screen can hold,
4845 // it is dealt with when the string is drawn (above).
4846
4847 else if ((ch >= 32) && (ch <= 126))
4848 if ((chat_index+1) < CHAT_STRING_BFR_SIZE)
4849 {
4850 if (shiftdown)
4851 ch = shiftxform[ch];
4852 if (chat_string_buffer[chat_index] == 0)
4853 {
4854 chat_string_buffer[chat_index++] = ch;
4855 chat_string_buffer[chat_index] = 0;
4856 }
4857 else
4858 chat_string_buffer[chat_index++] = ch;
4859 }
4860 return true;
4861 }
4862
4863 M_SelectDone(ptr1); // phares 4/17/98
4864 return true;
4865 }
4866
4867 // Not changing any items on the Setup screens. See if we're
4868 // navigating the Setup menus or selecting an item to change.
4869
4870 if (ch == key_menu_down)
4871 {
4872 ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
4873 do
4874 if (ptr1->m_flags & S_END)
4875 {
4876 set_menu_itemon = 0;
4877 ptr1 = current_setup_menu;
4878 }
4879 else
4880 {
4881 set_menu_itemon++;
4882 ptr1++;
4883 }
4884 while (ptr1->m_flags & S_SKIP);
4885 M_SelectDone(ptr1); // phares 4/17/98
4886 return true;
4887 }
4888
4889 if (ch == key_menu_up)
4890 {
4891 ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
4892 do
4893 {
4894 if (set_menu_itemon == 0)
4895 do
4896 set_menu_itemon++;
4897 while(!((current_setup_menu + set_menu_itemon)->m_flags & S_END));
4898 set_menu_itemon--;
4899 }
4900 while((current_setup_menu + set_menu_itemon)->m_flags & S_SKIP);
4901 M_SelectDone(current_setup_menu + set_menu_itemon); // phares 4/17/98
4902 return true;
4903 }
4904
4905 if (ch == key_menu_enter)
4906 {
4907 int flags = ptr1->m_flags;
4908
4909 // You've selected an item to change. Highlight it, post a new
4910 // message about what to do, and get ready to process the
4911 // change.
4912 //
4913 // killough 10/98: use friendlier char-based input buffer
4914
4915 if (flags & S_NUM)
4916 {
4917 setup_gather = true;
4918 print_warning_about_changes = false;
4919 gather_count = 0;
4920 }
4921 else if (flags & S_COLOR)
4922 {
4923 int color = *ptr1->var.def->location.pi;
4924
4925 if (color < 0 || color > 255) // range check the value
4926 color = 0; // 'no show' if invalid
4927
4928 color_palette_x = *ptr1->var.def->location.pi & 15;
4929 color_palette_y = *ptr1->var.def->location.pi >> 4;
4930 colorbox_active = true;
4931 }
4932 else if (flags & S_STRING)
4933 {
4934 // copy chat string into working buffer; trim if needed.
4935 // free the old chat string memory and replace it with
4936 // the (possibly larger) new memory for editing purposes
4937 //
4938 // killough 10/98: fix bugs, simplify
4939
4940 chat_string_buffer = malloc(CHAT_STRING_BFR_SIZE);
4941 strncpy(chat_string_buffer,
4942 *ptr1->var.def->location.ppsz, CHAT_STRING_BFR_SIZE);
4943
4944 // guarantee null delimiter
4945 chat_string_buffer[CHAT_STRING_BFR_SIZE-1] = 0;
4946
4947 // set chat table pointer to working buffer
4948 // and free old string's memory.
4949
4950 free((char*)*ptr1->var.def->location.ppsz);
4951 *ptr1->var.def->location.ppsz = chat_string_buffer;
4952 chat_index = 0; // current cursor position in chat_string_buffer
4953 }
4954 else if (flags & S_RESET)
4955 default_verify = true;
4956
4957 ptr1->m_flags |= S_SELECT;
4958 setup_select = true;
4959 S_StartSound(NULL,sfx_itemup);
4960 return true;
4961 }
4962
4963 if ((ch == key_menu_escape) || (ch == key_menu_backspace))
4964 {
4965 if (ch == key_menu_escape) // Clear all menus
4966 M_ClearMenus();
4967 else // key_menu_backspace = return to Setup Menu
4968 if (currentMenu->prevMenu)
4969 {
4970 currentMenu = currentMenu->prevMenu;
4971 itemOn = currentMenu->lastOn;
4972 S_StartSound(NULL,sfx_swtchn);
4973 }
4974 ptr1->m_flags &= ~(S_HILITE|S_SELECT);// phares 4/19/98
4975 setup_active = false;
4976 set_keybnd_active = false;
4977 set_weapon_active = false;
4978 set_status_active = false;
4979 set_auto_active = false;
4980 set_enemy_active = false;
4981 set_mess_active = false;
4982 set_chat_active = false;
4983 colorbox_active = false;
4984 default_verify = false; // phares 4/19/98
4985 set_general_active = false; // killough 10/98
4986 set_compat_active = false; // killough 10/98
4987 HU_Start(); // catch any message changes // phares 4/19/98
4988 S_StartSound(NULL,sfx_swtchx);
4989 return true;
4990 }
4991
4992 // Some setup screens may have multiple screens.
4993 // When there are multiple screens, m_prev and m_next items need to
4994 // be placed on the appropriate screen tables so the user can
4995 // move among the screens using the left and right arrow keys.
4996 // The m_var1 field contains a pointer to the appropriate screen
4997 // to move to.
4998
4999 if (ch == key_menu_left)
5000 {
5001 ptr2 = ptr1;
5002 do
5003 {
5004 ptr2++;
5005 if (ptr2->m_flags & S_PREV)
5006 {
5007 ptr1->m_flags &= ~S_HILITE;
5008 mult_screens_index--;
5009 current_setup_menu = ptr2->var.menu;
5010 set_menu_itemon = 0;
5011 print_warning_about_changes = false; // killough 10/98
5012 while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
5013 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
5014 S_StartSound(NULL,sfx_pstop); // killough 10/98
5015 return true;
5016 }
5017 }
5018 while (!(ptr2->m_flags & S_END));
5019 }
5020
5021 if (ch == key_menu_right)
5022 {
5023 ptr2 = ptr1;
5024 do
5025 {
5026 ptr2++;
5027 if (ptr2->m_flags & S_NEXT)
5028 {
5029 ptr1->m_flags &= ~S_HILITE;
5030 mult_screens_index++;
5031 current_setup_menu = ptr2->var.menu;
5032 set_menu_itemon = 0;
5033 print_warning_about_changes = false; // killough 10/98
5034 while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
5035 current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
5036 S_StartSound(NULL,sfx_pstop); // killough 10/98
5037 return true;
5038 }
5039 }
5040 while (!(ptr2->m_flags & S_END));
5041 }
5042
5043 } // End of Setup Screen processing
5044
5045 // From here on, these navigation keys are used on the BIG FONT menus
5046 // like the Main Menu.
5047
5048 if (ch == key_menu_down) // phares 3/7/98
5049 {
5050 do
5051 {
5052 if (itemOn+1 > currentMenu->numitems-1)
5053 itemOn = 0;
5054 else
5055 itemOn++;
5056 S_StartSound(NULL,sfx_pstop);
5057 }
5058 while(currentMenu->menuitems[itemOn].status==-1);
5059 return true;
5060 }
5061
5062 if (ch == key_menu_up) // phares 3/7/98
5063 {
5064 do
5065 {
5066 if (!itemOn)
5067 itemOn = currentMenu->numitems-1;
5068 else
5069 itemOn--;
5070 S_StartSound(NULL,sfx_pstop);
5071 }
5072 while(currentMenu->menuitems[itemOn].status==-1);
5073 return true;
5074 }
5075
5076 if (ch == key_menu_left) // phares 3/7/98
5077 {
5078 if (currentMenu->menuitems[itemOn].routine &&
5079 currentMenu->menuitems[itemOn].status == 2)
5080 {
5081 S_StartSound(NULL,sfx_stnmov);
5082 currentMenu->menuitems[itemOn].routine(0);
5083 }
5084 return true;
5085 }
5086
5087 if (ch == key_menu_right) // phares 3/7/98
5088 {
5089 if (currentMenu->menuitems[itemOn].routine &&
5090 currentMenu->menuitems[itemOn].status == 2)
5091 {
5092 S_StartSound(NULL,sfx_stnmov);
5093 currentMenu->menuitems[itemOn].routine(1);
5094 }
5095 return true;
5096 }
5097
5098 if (ch == key_menu_enter) // phares 3/7/98
5099 {
5100 if (currentMenu->menuitems[itemOn].routine &&
5101 currentMenu->menuitems[itemOn].status)
5102 {
5103 currentMenu->lastOn = itemOn;
5104 if (currentMenu->menuitems[itemOn].status == 2)
5105 {
5106 currentMenu->menuitems[itemOn].routine(1); // right arrow
5107 S_StartSound(NULL,sfx_stnmov);
5108 }
5109 else
5110 {
5111 currentMenu->menuitems[itemOn].routine(itemOn);
5112 S_StartSound(NULL,sfx_pistol);
5113 }
5114 }
5115 //jff 3/24/98 remember last skill selected
5116 // killough 10/98 moved to skill-specific functions
5117 return true;
5118 }
5119
5120 if (ch == key_menu_escape) // phares 3/7/98
5121 {
5122 currentMenu->lastOn = itemOn;
5123 M_ClearMenus ();
5124 S_StartSound(NULL,sfx_swtchx);
5125 return true;
5126 }
5127
5128 if (ch == key_menu_backspace) // phares 3/7/98
5129 {
5130 currentMenu->lastOn = itemOn;
5131
5132 // phares 3/30/98:
5133 // add checks to see if you're in the extended help screens
5134 // if so, stay with the same menu definition, but bump the
5135 // index back one. if the index bumps back far enough ( == 0)
5136 // then you can return to the Read_Thisn menu definitions
5137
5138 if (currentMenu->prevMenu)
5139 {
5140 if (currentMenu == &ExtHelpDef)
5141 {
5142 if (--extended_help_index == 0)
5143 {
5144 currentMenu = currentMenu->prevMenu;
5145 extended_help_index = 1; // reset
5146 }
5147 }
5148 else
5149 currentMenu = currentMenu->prevMenu;
5150 itemOn = currentMenu->lastOn;
5151 S_StartSound(NULL,sfx_swtchn);
5152 }
5153 return true;
5154 }
5155
5156 else
5157 {
5158 for (i = itemOn+1;i < currentMenu->numitems;i++)
5159 if (currentMenu->menuitems[i].alphaKey == ch)
5160 {
5161 itemOn = i;
5162 S_StartSound(NULL,sfx_pstop);
5163 return true;
5164 }
5165 for (i = 0;i <= itemOn;i++)
5166 if (currentMenu->menuitems[i].alphaKey == ch)
5167 {
5168 itemOn = i;
5169 S_StartSound(NULL,sfx_pstop);
5170 return true;
5171 }
5172 }
5173 return false;
5174}
5175
5176//
5177// End of M_Responder
5178//
5179/////////////////////////////////////////////////////////////////////////////
5180
5181/////////////////////////////////////////////////////////////////////////////
5182//
5183// General Routines
5184//
5185// This displays the Main menu and gets the menu screens rolling.
5186// Plus a variety of routines that control the Big Font menu display.
5187// Plus some initialization for game-dependant situations.
5188
5189void M_StartControlPanel (void)
5190{
5191 // intro might call this repeatedly
5192
5193 if (menuactive)
5194 return;
5195
5196 //jff 3/24/98 make default skill menu choice follow -skill or defaultskill
5197 //from command line or config file
5198 //
5199 // killough 10/98:
5200 // Fix to make "always floating" with menu selections, and to always follow
5201 // defaultskill, instead of -skill.
5202
5203 NewDef.lastOn = defaultskill - 1;
5204
5205 default_verify = 0; // killough 10/98
5206 menuactive = 1;
5207 currentMenu = &MainDef; // JDC
5208 itemOn = currentMenu->lastOn; // JDC
5209 print_warning_about_changes = false; // killough 11/98
5210}
5211
5212//
5213// M_Drawer
5214// Called after the view has been rendered,
5215// but before it has been blitted.
5216//
5217// killough 9/29/98: Significantly reformatted source
5218//
5219
5220void M_Drawer (void)
5221{
5222 inhelpscreens = false;
5223
5224 // Horiz. & Vertically center string and print it.
5225 // killough 9/29/98: simplified code, removed 40-character width limit
5226 if (messageToPrint)
5227 {
5228 /* cph - strdup string to writable memory */
5229 char *ms = strdup(messageString);
5230 char *p = ms;
5231
5232 int y = 100 - M_StringHeight(messageString)/2;
5233 while (*p)
5234 {
5235 char *string = p, c;
5236 while ((c = *p) && *p != '\n')
5237 p++;
5238 *p = 0;
5239 M_WriteText(160 - M_StringWidth(string)/2, y, string);
5240 y += hu_font[0].height;
5241 if ((*p = c))
5242 p++;
5243 }
5244 free(ms);
5245 }
5246 else
5247 if (menuactive)
5248 {
5249 int x,y,max,i;
5250
5251 if (currentMenu->routine)
5252 currentMenu->routine(); // call Draw routine
5253
5254 // DRAW MENU
5255
5256 x = currentMenu->x;
5257 y = currentMenu->y;
5258 max = currentMenu->numitems;
5259
5260 for (i=0;i<max;i++)
5261 {
5262 if (currentMenu->menuitems[i].name[0])
5263 V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name,
5264 CR_DEFAULT, VPT_STRETCH);
5265 y += LINEHEIGHT;
5266 }
5267
5268 // DRAW SKULL
5269
5270 // CPhipps - patch drawing updated
5271 V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0,
5272 skullName[whichSkull], CR_DEFAULT, VPT_STRETCH);
5273 }
5274}
5275
5276//
5277// M_ClearMenus
5278//
5279// Called when leaving the menu screens for the real world
5280
5281void M_ClearMenus (void)
5282{
5283 menuactive = 0;
5284 print_warning_about_changes = 0; // killough 8/15/98
5285 default_verify = 0; // killough 10/98
5286
5287 // if (!netgame && usergame && paused)
5288 // sendpause = true;
5289}
5290
5291//
5292// M_SetupNextMenu
5293//
5294void M_SetupNextMenu(menu_t *menudef)
5295{
5296 currentMenu = menudef;
5297 itemOn = currentMenu->lastOn;
5298}
5299
5300/////////////////////////////
5301//
5302// M_Ticker
5303//
5304void M_Ticker (void)
5305{
5306 if (--skullAnimCounter <= 0)
5307 {
5308 whichSkull ^= 1;
5309 skullAnimCounter = 8;
5310 }
5311}
5312
5313/////////////////////////////
5314//
5315// Message Routines
5316//
5317
5318void M_StartMessage (const char* string,void* routine,boolean input)
5319{
5320 messageLastMenuActive = menuactive;
5321 messageToPrint = 1;
5322 messageString = string;
5323 messageRoutine = routine;
5324 messageNeedsInput = input;
5325 menuactive = true;
5326 return;
5327}
5328
5329void M_StopMessage(void)
5330{
5331 menuactive = messageLastMenuActive;
5332 messageToPrint = 0;
5333}
5334
5335/////////////////////////////
5336//
5337// Thermometer Routines
5338//
5339
5340//
5341// M_DrawThermo draws the thermometer graphic for Mouse Sensitivity,
5342// Sound Volume, etc.
5343//
5344// proff/nicolas 09/20/98 -- changed for hi-res
5345// CPhipps - patch drawing updated
5346//
5347void M_DrawThermo(int x,int y,int thermWidth,int thermDot )
5348 {
5349 int xx;
5350 int i;
5351 /*
5352 * Modification By Barry Mead to allow the Thermometer to have vastly
5353 * larger ranges. (the thermWidth parameter can now have a value as
5354 * large as 200. Modified 1-9-2000 Originally I used it to make
5355 * the sensitivity range for the mouse better. It could however also
5356 * be used to improve the dynamic range of music and sound affect
5357 * volume controls for example.
5358 */
5359 int horizScaler; //Used to allow more thermo range for mouse sensitivity.
5360 thermWidth = (thermWidth > 200) ? 200 : thermWidth; //Clamp to 200 max
5361 horizScaler = (thermWidth > 23) ? (200 / thermWidth) : 8; //Dynamic range
5362 xx = x;
5363 V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH);
5364 xx += 8;
5365 for (i=0;i<thermWidth;i++)
5366 {
5367 V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
5368 xx += horizScaler;
5369 }
5370
5371 xx += (8 - horizScaler); /* make the right end look even */
5372
5373 V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
5374 V_DrawNamePatch((x+8)+thermDot*horizScaler,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
5375 }
5376
5377//
5378// Draw an empty cell in the thermometer
5379//
5380
5381void M_DrawEmptyCell (menu_t* menu,int item)
5382{
5383 // CPhipps - patch drawing updated
5384 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
5385 "M_CELL1", CR_DEFAULT, VPT_STRETCH);
5386}
5387
5388//
5389// Draw a full cell in the thermometer
5390//
5391
5392void M_DrawSelCell (menu_t* menu,int item)
5393{
5394 // CPhipps - patch drawing updated
5395 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
5396 "M_CELL2", CR_DEFAULT, VPT_STRETCH);
5397}
5398
5399/////////////////////////////
5400//
5401// String-drawing Routines
5402//
5403
5404//
5405// Find string width from hu_font chars
5406//
5407
5408int M_StringWidth(const char* string)
5409{
5410 int i, c, w = 0;
5411 for (i = 0;(size_t)i < strlen(string);i++)
5412 w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ?
5413 4 : hu_font[c].width;
5414 return w;
5415}
5416
5417//
5418// Find string height from hu_font chars
5419//
5420
5421int M_StringHeight(const char* string)
5422{
5423 int i, h, height = h = hu_font[0].height;
5424 for (i = 0;string[i];i++) // killough 1/31/98
5425 if (string[i] == '\n')
5426 h += height;
5427 return h;
5428}
5429
5430//
5431// Write a string using the hu_font
5432//
5433void M_WriteText (int x,int y,const char* string)
5434{
5435 int w;
5436 const char* ch;
5437 int c;
5438 int cx;
5439 int cy;
5440
5441 ch = string;
5442 cx = x;
5443 cy = y;
5444
5445 while(1) {
5446 c = *ch++;
5447 if (!c)
5448 break;
5449 if (c == '\n') {
5450 cx = x;
5451 cy += 12;
5452 continue;
5453 }
5454
5455 c = toupper(c) - HU_FONTSTART;
5456 if (c < 0 || c>= HU_FONTSIZE) {
5457 cx += 4;
5458 continue;
5459 }
5460
5461 w = hu_font[c].width;
5462 if (cx+w > SCREENWIDTH)
5463 break;
5464 // proff/nicolas 09/20/98 -- changed for hi-res
5465 // CPhipps - patch drawing updated
5466 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
5467 cx+=w;
5468 }
5469}
5470
5471/////////////////////////////
5472//
5473// Initialization Routines to take care of one-time setup
5474//
5475
5476// phares 4/08/98:
5477// M_InitHelpScreen() clears the weapons from the HELP
5478// screen that don't exist in this version of the game.
5479
5480void M_InitHelpScreen(void)
5481{
5482 setup_menu_t* src;
5483
5484 src = helpstrings;
5485 while (!(src->m_flags & S_END)) {
5486
5487 if ((strncmp(src->m_text,"PLASMA",6) == 0) && (gamemode == shareware))
5488 src->m_flags = S_SKIP; // Don't show setting or item
5489 if ((strncmp(src->m_text,"BFG",3) == 0) && (gamemode == shareware))
5490 src->m_flags = S_SKIP; // Don't show setting or item
5491 if ((strncmp(src->m_text,"SSG",3) == 0) && (gamemode != commercial))
5492 src->m_flags = S_SKIP; // Don't show setting or item
5493 src++;
5494 }
5495}
5496
5497//
5498// M_Init
5499//
5500void M_Init(void)
5501{
5502 M_InitDefaults(); // killough 11/98
5503 currentMenu = &MainDef;
5504 menuactive = 0;
5505 itemOn = currentMenu->lastOn;
5506 whichSkull = 0;
5507 skullAnimCounter = 10;
5508 screenSize = screenblocks - 3;
5509 messageToPrint = 0;
5510 messageString = NULL;
5511 messageLastMenuActive = menuactive;
5512 quickSaveSlot = -1;
5513
5514 // Here we could catch other version dependencies,
5515 // like HELP1/2, and four episodes.
5516
5517 switch(gamemode)
5518 {
5519 case commercial:
5520 // This is used because DOOM 2 had only one HELP
5521 // page. I use CREDIT as second page now, but
5522 // kept this hack for educational purposes.
5523 MainMenu[readthis] = MainMenu[quitdoom];
5524 MainDef.numitems--;
5525 MainDef.y += 8;
5526 NewDef.prevMenu = &MainDef;
5527 ReadDef1.routine = M_DrawReadThis1;
5528 ReadDef1.x = 330;
5529 ReadDef1.y = 165;
5530 ReadMenu1[0].routine = M_FinishReadThis;
5531 break;
5532 case registered:
5533 // Episode 2 and 3 are handled,
5534 // branching to an ad screen.
5535
5536 // killough 2/21/98: Fix registered Doom help screen
5537 // killough 10/98: moved to second screen, moved up to the top
5538 ReadDef2.y = 15;
5539
5540 case shareware:
5541 // We need to remove the fourth episode.
5542 EpiDef.numitems--;
5543 break;
5544 case retail:
5545 // We are fine.
5546 default:
5547 break;
5548 }
5549
5550 M_InitHelpScreen(); // init the help screen // phares 4/08/98
5551 M_InitExtendedHelp(); // init extended help screens // phares 3/30/98
5552
5553 M_ChangeDemoSmoothTurns();
5554}
5555
5556//
5557// End of General Routines
5558//
5559/////////////////////////////////////////////////////////////////////////////