Fix a bunch of 'variable set but not used' warnings reported from GCC 4.6.0.
[kugel-rb.git] / apps / plugins / doom / m_menu.c
blobaa82959aaf3c3c20808c2737a33290dba935e284
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // $Log$
19 // Revision 1.7 2006/12/13 04:44:17 kkurbjun
20 // Dehacked and BEX support for Doom - currently only supports a DEHACKED file in a WAD (not as a standalone file yet).
22 // Revision 1.6 2006-04-16 23:14:04 kkurbjun
23 // Fix run so that it stays enabled across level loads. Removed some unused code and added some back in for hopeful future use.
25 // Revision 1.5 2006-04-04 23:58:37 kkurbjun
26 // Make savegame strings more informative
28 // Revision 1.4 2006-04-04 23:13:50 kkurbjun
29 // Fix up configurable keys, edit exit string, more work needs to be done on menu keys
31 // Revision 1.3 2006-04-03 20:03:02 kkurbjun
32 // Updates doom menu w/ new graphics, now requires rockdoom.wad: http://alamode.mines.edu/~kkurbjun/rockdoom.wad
34 // Revision 1.2 2006-04-03 00:28:13 kkurbjun
35 // Fixes graphic errors in scaling code, note sure about the fix in hu_lib.c though. I havn't seen any corrupted text but it may still need a proper fix.
37 // Revision 1.1 2006-03-28 15:44:01 dave
38 // Patch #2969 - Doom! Currently only working on the H300.
41 // DESCRIPTION:
42 // DOOM selection menu, options, episode etc.
43 // Sliders and icons. Kinda widget stuff.
45 //-----------------------------------------------------------------------------
47 #include "doomdef.h"
48 #include "dstrings.h"
50 #include "d_main.h"
52 #include "i_system.h"
53 #include "i_video.h"
54 #include "z_zone.h"
55 #include "v_video.h"
56 #include "w_wad.h"
58 #include "r_main.h"
59 #include "d_deh.h"
60 #include "hu_stuff.h"
62 #include "g_game.h"
64 #include "m_argv.h"
65 #include "m_swap.h"
66 #include "s_sound.h"
68 #include "doomstat.h"
70 // Data.
71 #include "sounds.h"
73 #include "m_menu.h"
74 #include "rockmacros.h"
77 extern patchnum_t hu_font[HU_FONTSIZE];
78 extern boolean message_dontfuckwithme;
80 extern boolean chat_on; // in heads-up code
83 // defaulted values
85 int mouseSensitivity; // has default
87 // Show messages has default, 0 = off, 1 = on
88 int showMessages;
90 // Blocky mode, has default, 0 = high, 1 = normal
91 int screenblocks; // has default
93 // temp for screenblocks (0-9)
94 int screenSize;
96 // -1 = no quicksave slot picked!
97 int quickSaveSlot;
99 // 1 = message to be printed
100 int messageToPrint;
101 // ...and here is the message string!
102 const char* messageString;
104 // message x & y
105 int messx;
106 int messy;
107 int messageLastMenuActive;
109 // timed message = no input from user
110 boolean messageNeedsInput;
112 void (*messageRoutine)(int response);
114 #define SAVESTRINGSIZE 24
116 // we are going to be entering a savegame string
117 int saveStringEnter;
118 int saveSlot; // which slot to save in
119 int saveCharIndex; // which char we're editing
120 // old save description before edit
121 char saveOldString[SAVESTRINGSIZE];
123 boolean inhelpscreens;
124 boolean menuactive;
126 #define SKULLXOFF -32
127 #define LINEHEIGHT 16
129 extern boolean sendpause;
130 char savegamestrings[10][SAVESTRINGSIZE];
132 char endstring[170];
136 // MENU TYPEDEFS
138 typedef struct
140 // 0 = no cursor here, 1 = ok, 2 = arrows ok
141 short status;
143 char name[10];
145 // choice = menu item #.
146 // if status = 2,
147 // choice=0:leftarrow,1:rightarrow
148 void (*routine)(int choice);
150 // hotkey in menu
151 char alphaKey;
153 menuitem_t;
157 typedef struct menu_s
159 short numitems; // # of menu items
160 struct menu_s* prevMenu; // previous menu
161 menuitem_t* menuitems; // menu items
162 void (*routine)(void); // draw routine ROCKBOX
163 short x;
164 short y; // x,y of menu
165 short lastOn; // last item user was on in menu
167 menu_t;
169 short itemOn; // menu item skull is on
170 short skullAnimCounter; // skull animation counter
171 short whichSkull; // which skull to draw
172 int systemvol;
174 // graphic name of skulls
175 // warning: initializer-string for array of chars is too long
176 char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
178 // current menudef
179 menu_t* currentMenu;
182 // PROTOTYPES
184 void M_NewGame(int choice);
185 void M_Episode(int choice);
186 void M_ChooseSkill(int choice);
187 void M_LoadGame(int choice);
188 void M_SaveGame(int choice);
189 void M_Options(int choice);
190 void M_EndGame(int choice);
191 void M_ReadThis(int choice);
192 void M_ReadThis2(int choice);
193 void M_QuitDOOM(int choice);
195 void M_ChangeMessages(int choice);
196 void M_ChangeGamma(int choice);
197 void M_SfxVol(int choice);
198 void M_MusicVol(int choice);
199 void M_SystemVol(int choice);
200 void M_SizeDisplay(int choice);
201 void M_StartGame(int choice);
202 void M_Sound(int choice);
204 void M_FinishReadThis(int choice);
205 void M_LoadSelect(int choice);
206 void M_SaveSelect(int choice);
207 void M_ReadSaveStrings(void);
208 void M_QuickSave(void);
209 void M_QuickLoad(void);
211 void M_DrawMainMenu(void);
212 void M_DrawReadThis1(void);
213 void M_DrawReadThis2(void);
214 void M_DrawNewGame(void);
215 void M_DrawEpisode(void);
216 void M_DrawOptions(void);
217 void M_DrawSound(void);
218 void M_DrawLoad(void);
219 void M_DrawSave(void);
221 void M_DrawSaveLoadBorder(int x,int y);
222 void M_SetupNextMenu(menu_t *menudef);
223 void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
224 void M_DrawEmptyCell(menu_t *menu,int item);
225 void M_DrawSelCell(menu_t *menu,int item);
226 void M_WriteText(int x, int y, char *string);
227 int M_StringWidth(const char* string);
228 int M_StringHeight(const char* string);
229 void M_StartControlPanel(void);
230 void M_StartMessage(const char *string,void *routine,boolean input);
231 void M_StopMessage(void);
232 void M_ClearMenus (void);
238 // DOOM MENU
240 enum
242 newgame = 0,
243 options,
244 loadgame,
245 savegame,
246 readthis,
247 quitdoom,
248 main_end
250 unsigned main_e;
252 menuitem_t MainMenu[]=
254 {1,"M_NGAME",M_NewGame,'n'},
255 {1,"M_OPTION",M_Options,'o'},
256 {1,"M_LOADG",M_LoadGame,'l'},
257 {1,"M_SAVEG",M_SaveGame,'s'},
258 // Another hickup with Special edition.
259 {1,"M_RDTHIS",M_ReadThis,'r'},
260 {1,"M_QUITG",M_QuitDOOM,'q'}
263 menu_t MainDef =
265 main_end,
266 NULL,
267 MainMenu,
268 M_DrawMainMenu,
269 97,64,
275 // EPISODE SELECT
277 enum
279 ep1,
280 ep2,
281 ep3,
282 ep4,
283 ep_end
285 unsigned episodes_e;
287 menuitem_t EpisodeMenu[]=
289 {1,"M_EPI1", M_Episode,'k'},
290 {1,"M_EPI2", M_Episode,'t'},
291 {1,"M_EPI3", M_Episode,'i'},
292 {1,"M_EPI4", M_Episode,'t'}
295 menu_t EpiDef =
297 ep_end, // # of menu items
298 &MainDef, // previous menu
299 EpisodeMenu, // menuitem_t ->
300 M_DrawEpisode, // drawing routine ->
301 48,63, // x,y
302 ep1 // lastOn
306 // NEW GAME
308 enum
310 killthings,
311 toorough,
312 hurtme,
313 violence,
314 nightmare,
315 newg_end
317 unsigned newgame_e;
319 menuitem_t NewGameMenu[]=
321 {1,"M_JKILL", M_ChooseSkill, 'i'},
322 {1,"M_ROUGH", M_ChooseSkill, 'h'},
323 {1,"M_HURT", M_ChooseSkill, 'h'},
324 {1,"M_ULTRA", M_ChooseSkill, 'u'},
325 {1,"M_NMARE", M_ChooseSkill, 'n'}
328 menu_t NewDef =
330 newg_end, // # of menu items
331 &EpiDef, // previous menu
332 NewGameMenu, // menuitem_t ->
333 M_DrawNewGame, // drawing routine ->
334 48,63, // x,y
335 hurtme // lastOn
341 // OPTIONS MENU
343 enum
345 endgame,
346 messages,
347 scrnsize,
348 option_empty1,
349 gamasens,
350 option_empty2,
351 soundvol,
352 opt_end
354 unsigned options_e;
356 menuitem_t OptionsMenu[]=
358 {1,"M_ENDGAM", M_EndGame,'e'},
359 {1,"M_MESSG", M_ChangeMessages,'m'},
360 {2,"M_SCRNSZ", M_SizeDisplay,'s'},
361 {-1,"",0,0},
362 {2,"M_GAMMA", M_ChangeGamma,'m'},
363 {-1,"",0,0},
364 {1,"M_SVOL", M_Sound,'s'}
367 menu_t OptionsDef =
369 opt_end,
370 &MainDef,
371 OptionsMenu,
372 M_DrawOptions,
373 60,37,
378 // Read This! MENU 1 & 2
380 enum
382 rdthsempty1,
383 read1_end
385 unsigned read_e;
387 menuitem_t ReadMenu1[] =
389 {1,"",M_ReadThis2,0}
392 menu_t ReadDef1 =
394 read1_end,
395 &MainDef,
396 ReadMenu1,
397 M_DrawReadThis1,
398 280,185,
402 enum
404 rdthsempty2,
405 read2_end
407 unsigned read_e2;
409 menuitem_t ReadMenu2[]=
411 {1,"",M_FinishReadThis,0}
414 menu_t ReadDef2 =
416 read2_end,
417 &ReadDef1,
418 ReadMenu2,
419 M_DrawReadThis2,
420 330,175,
425 // SOUND VOLUME MENU
427 enum
429 sfx_vol,
430 sfx_empty1,
431 music_vol,
432 sfx_empty2,
433 system_vol,
434 sfx_empty3,
435 sound_end
437 unsigned sound_e;
439 menuitem_t SoundMenu[]=
441 {2,"M_SFXVOL",M_SfxVol,'s'},
442 {-1,"",0,0}, //ROCKBOX
443 {2,"M_MUSVOL",M_MusicVol,'m'},
444 {-1,"",0,0}, //ROCKBOX
445 {2,"M_SYSVOL",M_SystemVol,'z'},
446 {-1,"",0,0} //ROCKBOX
449 menu_t SoundDef =
451 sound_end,
452 &OptionsDef,
453 SoundMenu,
454 M_DrawSound,
455 80,64,
460 // LOAD GAME MENU
462 enum
464 load1,
465 load2,
466 load3,
467 load4,
468 load5,
469 load6,
470 load_end
472 unsigned load_e;
474 menuitem_t LoadMenu[]=
476 {1,"", M_LoadSelect,'1'},
477 {1,"", M_LoadSelect,'2'},
478 {1,"", M_LoadSelect,'3'},
479 {1,"", M_LoadSelect,'4'},
480 {1,"", M_LoadSelect,'5'},
481 {1,"", M_LoadSelect,'6'}
484 menu_t LoadDef =
486 load_end,
487 &MainDef,
488 LoadMenu,
489 M_DrawLoad,
490 80,54,
495 // SAVE GAME MENU
497 menuitem_t SaveMenu[]=
499 {1,"", M_SaveSelect,'1'},
500 {1,"", M_SaveSelect,'2'},
501 {1,"", M_SaveSelect,'3'},
502 {1,"", M_SaveSelect,'4'},
503 {1,"", M_SaveSelect,'5'},
504 {1,"", M_SaveSelect,'6'}
507 menu_t SaveDef =
509 load_end,
510 &MainDef,
511 SaveMenu,
512 M_DrawSave,
513 80,54,
519 // M_ReadSaveStrings
520 // read the strings from the savegame files
522 void M_ReadSaveStrings(void)
524 int handle;
525 int i;
526 char name[256];
528 for (i = 0;i < load_end;i++)
530 if (M_CheckParm("-cdrom"))
531 snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i);
532 else
533 snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",i);
535 handle = open (name, O_RDONLY | 0);
536 if (handle == -1)
538 strcpy(&savegamestrings[i][0],EMPTYSTRING);
539 LoadMenu[i].status = 0;
540 continue;
542 read (handle, &savegamestrings[i], SAVESTRINGSIZE);
543 close (handle);
544 LoadMenu[i].status = 1;
548 #define LOADGRAPHIC_Y 8
550 // M_LoadGame & Cie.
552 void M_DrawLoad(void)
554 int i;
556 V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH);
557 for (i = 0;i < load_end; i++)
559 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
560 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
567 // Draw border for the savegame description
569 void M_DrawSaveLoadBorder(int x,int y)
571 int i;
573 V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH);
574 for (i = 0;i < 24;i++)
576 V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH);
577 x += 8;
579 V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH);
585 // User wants to load this game
587 void M_LoadSelect(int choice)
589 char name[256];
591 if (M_CheckParm("-cdrom"))
592 snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice);
593 else
594 snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",choice);
595 G_LoadGame (choice, false);
596 M_ClearMenus ();
600 // Selected from DOOM menu
602 void M_LoadGame (int choice)
604 (void)choice;
605 if (netgame)
607 M_StartMessage(LOADNET,NULL,false);
608 return;
611 M_SetupNextMenu(&LoadDef);
612 M_ReadSaveStrings();
617 // M_SaveGame & Cie.
619 void M_DrawSave(void)
621 int i;
623 V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH);
624 for (i = 0;i < load_end; i++)
626 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
627 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
630 if (saveStringEnter)
632 i = M_StringWidth(savegamestrings[saveSlot]);
633 M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
638 // M_Responder calls this when user is finished
640 void M_DoSave(int slot)
642 G_SaveGame (slot,savegamestrings[slot]);
643 M_ClearMenus ();
645 // PICK QUICKSAVE SLOT YET?
646 if (quickSaveSlot == -2)
647 quickSaveSlot = slot;
651 // User wants to save. Start string input for M_Responder
653 void M_SaveSelect(int choice)
655 // we are going to be intercepting all chars
656 saveStringEnter = 1;
658 saveSlot = choice;
659 snprintf(savegamestrings[choice], sizeof(savegamestrings[choice]),
660 (gamemode==shareware||gamemode==registered||gamemode==retail) ?
661 *mapnames[(gameepisode-1)*9+gamemap-1] : (gamemission==doom2) ?
662 *mapnames2[gamemap-1] : (gamemission==pack_plut) ?
663 *mapnamesp[gamemap-1] : (gamemission==pack_tnt) ?
664 *mapnamest[gamemap-1] : "Unknown Location", choice);
665 if (!strcmp(savegamestrings[choice],s_EMPTYSTRING))
666 savegamestrings[choice][0] = 0;
667 saveCharIndex = strlen(savegamestrings[choice]);
671 // Selected from DOOM menu
673 void M_SaveGame (int choice)
675 (void)choice;
676 if (!usergame)
678 M_StartMessage(s_SAVEDEAD,NULL,false);
679 return;
682 if (gamestate != GS_LEVEL)
683 return;
685 M_SetupNextMenu(&SaveDef);
686 M_ReadSaveStrings();
692 // M_QuickSave
694 char tempstring[80];
696 void M_QuickSaveResponse(int ch)
698 if (ch == 'y')
700 M_DoSave(quickSaveSlot);
702 S_StartSound(NULL,sfx_swtchx);
707 void M_QuickSave(void)
709 if (!usergame)
711 S_StartSound(NULL,sfx_oof);
712 return;
715 if (gamestate != GS_LEVEL)
716 return;
718 if (quickSaveSlot < 0)
720 M_StartControlPanel();
721 M_ReadSaveStrings();
722 M_SetupNextMenu(&SaveDef);
723 quickSaveSlot = -2; // means to pick a slot now
724 return;
726 snprintf(tempstring,sizeof(tempstring),s_QSPROMPT,savegamestrings[quickSaveSlot]);
727 M_StartMessage(tempstring,M_QuickSaveResponse,true);
733 // M_QuickLoad
735 void M_QuickLoadResponse(int ch)
737 if (ch == 'y')
739 M_LoadSelect(quickSaveSlot);
740 S_StartSound(NULL,sfx_swtchx);
745 void M_QuickLoad(void)
747 if (netgame)
749 M_StartMessage(QLOADNET,NULL,false);
750 return;
753 if (quickSaveSlot < 0)
755 M_StartMessage(QSAVESPOT,NULL,false);
756 return;
758 snprintf(tempstring, sizeof(tempstring), QLPROMPT,savegamestrings[quickSaveSlot]);
759 M_StartMessage(tempstring,M_QuickLoadResponse,true);
766 // Read This Menus
767 // Had a "quick hack to fix romero bug"
769 void M_DrawReadThis1(void)
771 inhelpscreens = true;
772 switch ( gamemode )
774 case commercial:
775 V_DrawNamePatch(0, 0, 0, "HELP", CR_DEFAULT, VPT_STRETCH);
776 break;
777 case shareware:
778 case registered:
779 case retail:
780 V_DrawNamePatch(0, 0, 0, "HELP1", CR_DEFAULT, VPT_STRETCH);
781 break;
782 default:
783 break;
785 return;
791 // Read This Menus - optional second page.
793 void M_DrawReadThis2(void)
795 inhelpscreens = true;
796 switch ( gamemode )
798 case retail:
799 case commercial:
800 // This hack keeps us from having to change menus.
801 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
802 break;
803 case shareware:
804 case registered:
805 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
806 break;
807 default:
808 break;
810 return;
815 // Change Sfx & Music volumes
817 void M_DrawSound(void)
819 int sysmax=(rb->sound_max(SOUND_VOLUME)-rb->sound_min(SOUND_VOLUME));
820 V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH);
822 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
823 16,snd_SfxVolume);
825 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
826 16,snd_MusicVolume);
828 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(system_vol+1),
829 16,(sysmax+systemvol)/5);
832 void M_Sound(int choice)
834 (void) choice;
835 M_SetupNextMenu(&SoundDef);
838 void M_SfxVol(int choice)
840 switch(choice)
842 case 0:
843 if (snd_SfxVolume)
844 snd_SfxVolume--;
845 break;
846 case 1:
847 if (snd_SfxVolume < 15)
848 snd_SfxVolume++;
849 break;
852 S_SetSfxVolume(snd_SfxVolume /* *8 */);
855 void M_MusicVol(int choice)
857 switch(choice)
859 case 0:
860 if (snd_MusicVolume)
861 snd_MusicVolume--;
862 break;
863 case 1:
864 if (snd_MusicVolume < 15)
865 snd_MusicVolume++;
866 break;
869 S_SetMusicVolume(snd_MusicVolume /* *8 */);
872 void M_SystemVol(int choice)
874 switch(choice)
876 case 0:
877 if (systemvol-5>rb->sound_min(SOUND_VOLUME))
879 systemvol-=5;
880 rb->sound_set(SOUND_VOLUME, systemvol);
881 rb->global_settings->volume = systemvol;
883 break;
884 case 1:
885 if (systemvol+5<rb->sound_max(SOUND_VOLUME))
887 systemvol+=5;
888 rb->sound_set(SOUND_VOLUME, systemvol);
889 rb->global_settings->volume = systemvol;
891 break;
896 // M_DrawMainMenu
898 void M_DrawMainMenu(void)
900 V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH);
907 // M_NewGame
909 void M_DrawNewGame(void)
911 // CPhipps - patch drawing updated
912 V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH);
913 V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH);
916 void M_NewGame(int choice)
918 (void) choice;
919 if (netgame && !demoplayback)
921 M_StartMessage(s_NEWGAME,NULL,false);
922 return;
925 if ( gamemode == commercial )
926 M_SetupNextMenu(&NewDef);
927 else
928 M_SetupNextMenu(&EpiDef);
933 // M_Episode
935 int epi;
937 void M_DrawEpisode(void)
939 // CPhipps - patch drawing updated
940 V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH);
943 void M_VerifyNightmare(int ch)
945 if (ch != key_menu_enter)
946 return;
948 G_DeferedInitNew(nightmare,epi+1,1);
949 M_ClearMenus ();
952 void M_ChooseSkill(int choice)
954 if (choice == nightmare)
956 M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true);
957 return;
960 //jff 3/24/98 remember last skill selected
961 // killough 10/98 moved to here
962 defaultskill = choice+1;
964 G_DeferedInitNew(choice,epi+1,1);
965 M_ClearMenus ();
968 void M_Episode(int choice)
970 if ( (gamemode == shareware)
971 && choice)
973 M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized
974 M_SetupNextMenu(&ReadDef1);
975 return;
978 // Yet another hack...
979 if ( (gamemode == registered)
980 && (choice > 2))
982 /* Digita */
983 // fprintf( stderr,
984 // "M_Episode: 4th episode requires UltimateDOOM\n");
985 choice = 0;
988 epi = choice;
989 M_SetupNextMenu(&NewDef);
995 // M_Options
997 char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
998 char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
1001 void M_DrawOptions(void)
1003 // CPhipps - patch drawing updated
1004 V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH);
1006 V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0,
1007 msgNames[showMessages], CR_DEFAULT, VPT_STRETCH);
1009 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(gamasens+1),
1010 4,usegamma);
1012 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
1013 9,screenSize);
1016 void M_Options(int choice)
1018 (void)choice;
1019 M_SetupNextMenu(&OptionsDef);
1025 // Toggle messages on/off
1027 void M_ChangeMessages(int choice)
1029 (void)choice;
1030 showMessages = 1 - showMessages;
1032 if (!showMessages)
1033 players[consoleplayer].message = s_MSGOFF;
1034 else
1035 players[consoleplayer].message = s_MSGON ;
1037 message_dontfuckwithme = true;
1042 // M_EndGame
1044 void M_EndGameResponse(int ch)
1046 if (ch != key_menu_enter)
1047 return;
1049 // killough 5/26/98: make endgame quit if recording or playing back demo
1050 if (demorecording || singledemo)
1051 G_CheckDemoStatus();
1053 currentMenu->lastOn = itemOn;
1054 M_ClearMenus ();
1055 D_StartTitle ();
1058 void M_EndGame(int choice)
1060 (void)choice;
1061 if (!usergame)
1063 S_StartSound(NULL,sfx_oof);
1064 return;
1067 if (netgame)
1069 M_StartMessage(s_NETEND,NULL,false);
1070 return;
1073 M_StartMessage(s_ENDGAME,M_EndGameResponse,true);
1080 // M_ReadThis
1082 void M_ReadThis(int choice)
1084 (void)choice;
1085 M_SetupNextMenu(&ReadDef1);
1088 void M_ReadThis2(int choice)
1090 (void)choice;
1091 M_SetupNextMenu(&ReadDef2);
1094 void M_FinishReadThis(int choice)
1096 (void)choice;
1097 M_SetupNextMenu(&MainDef);
1104 // M_QuitDOOM
1106 int quitsounds[8] =
1108 sfx_pldeth,
1109 sfx_dmpain,
1110 sfx_popain,
1111 sfx_slop,
1112 sfx_telept,
1113 sfx_posit1,
1114 sfx_posit3,
1115 sfx_sgtatk
1118 int quitsounds2[8] =
1120 sfx_vilact,
1121 sfx_getpow,
1122 sfx_boscub,
1123 sfx_slop,
1124 sfx_skeswg,
1125 sfx_kntdth,
1126 sfx_bspact,
1127 sfx_sgtatk
1132 void M_QuitResponse(int ch)
1134 if (ch != key_menu_enter)
1135 return;
1136 if (!netgame)
1138 if (gamemode == commercial)
1139 S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
1140 else
1141 S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
1142 I_WaitVBL(105);
1144 I_Quit ();
1150 void M_QuitDOOM(int choice)
1152 (void)choice;
1153 // We pick index 0 which is language sensitive,
1154 // or one at random, between 1 and maximum number.
1155 if (language != english )
1156 snprintf(endstring,sizeof(endstring),"%s\n\n%s",s_DOSY, endmsg[0] );
1157 else
1158 snprintf(endstring,sizeof(endstring),"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY);
1160 M_StartMessage(endstring,M_QuitResponse,true);
1166 void M_ChangeGamma(int choice)
1168 switch(choice)
1170 case 0:
1171 if (usegamma)
1172 usegamma--;
1173 break;
1174 case 1:
1175 if (usegamma < 4)
1176 usegamma++;
1177 break;
1179 V_SetPalette (0);
1182 void M_SizeDisplay(int choice)
1184 switch(choice)
1186 case 0:
1187 if (screenSize > 0)
1189 screenblocks--;
1190 screenSize--;
1192 break;
1193 case 1:
1194 if (screenSize < 8)
1196 screenblocks++;
1197 screenSize++;
1199 break;
1203 R_SetViewSize (screenblocks);
1210 // Menu Functions
1212 void
1213 M_DrawThermo
1214 ( int x,
1215 int y,
1216 int thermWidth,
1217 int thermDot )
1219 int xx;
1220 int i;
1222 xx = x;
1223 V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH);
1224 xx += 8;
1225 for (i=0;i<thermWidth;i++)
1227 V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
1228 xx += 8;
1230 V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
1231 V_DrawNamePatch((x+8)+thermDot*8,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
1236 void
1237 M_DrawEmptyCell
1238 ( menu_t* menu,
1239 int item )
1241 // CPhipps - patch drawing updated
1242 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
1243 "M_CELL1", CR_DEFAULT, VPT_STRETCH);
1246 void
1247 M_DrawSelCell
1248 ( menu_t* menu,
1249 int item )
1251 // CPhipps - patch drawing updated
1252 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
1253 "M_CELL2", CR_DEFAULT, VPT_STRETCH);
1257 void
1258 M_StartMessage
1259 ( const char* string,
1260 void* routine,
1261 boolean input )
1263 messageLastMenuActive = menuactive;
1264 messageToPrint = 1;
1265 messageString = string;
1266 messageRoutine = routine;
1267 messageNeedsInput = input;
1268 menuactive = true;
1269 return;
1274 void M_StopMessage(void)
1276 menuactive = messageLastMenuActive;
1277 messageToPrint = 0;
1283 // Find string width from hu_font chars
1285 int M_StringWidth(const char* string)
1287 int i, c, w = 0;
1288 for (i = 0;(size_t)i < strlen(string);i++)
1289 w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ?
1290 4 : SHORT(hu_font[c].width);
1291 return w;
1295 // Find string height from hu_font chars
1298 int M_StringHeight(const char* string)
1300 int i, h, height = h = SHORT(hu_font[0].height);
1301 for (i = 0;string[i];i++) // killough 1/31/98
1302 if (string[i] == '\n')
1303 h += height;
1304 return h;
1309 // Write a string using the hu_font
1311 void
1312 M_WriteText
1313 ( int x,
1314 int y,
1315 char* string)
1317 int w;
1318 char* ch;
1319 int c;
1320 int cx;
1321 int cy;
1324 ch = string;
1325 cx = x;
1326 cy = y;
1328 while(1)
1330 c = *ch++;
1331 if (!c)
1332 break;
1333 if (c == '\n')
1335 cx = x;
1336 cy += 12;
1337 continue;
1340 c = toupper(c) - HU_FONTSTART;
1341 if (c < 0 || c>= HU_FONTSIZE)
1343 cx += 4;
1344 continue;
1347 w = SHORT (hu_font[c].width);
1348 if (cx+w > 320)
1349 break;
1350 // proff/nicolas 09/20/98 -- changed for hi-res
1351 // CPhipps - patch drawing updated
1352 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
1353 cx+=w;
1360 // CONTROL PANEL
1364 // M_Responder
1366 boolean M_Responder (event_t* ev)
1368 int ch;
1369 int i;
1370 // static int joywait = 0;
1371 // static int mousewait = 0;
1372 // static int mousey = 0;
1373 // static int lasty = 0;
1374 // static int mousex = 0;
1375 // static int lastx = 0;
1377 ch = -1;
1379 // Process joystick input
1381 /* if (ev->type == ev_joystick && joywait < I_GetTime())
1383 if (ev->data3 == -1)
1385 ch = KEY_UPARROW;
1386 joywait = I_GetTime() + 5;
1388 else if (ev->data3 == 1)
1390 ch = KEY_DOWNARROW;
1391 joywait = I_GetTime() + 5;
1394 if (ev->data2 == -1)
1396 ch = KEY_LEFTARROW;
1397 joywait = I_GetTime() + 2;
1399 else if (ev->data2 == 1)
1401 ch = KEY_RIGHTARROW;
1402 joywait = I_GetTime() + 2;
1405 if (ev->data1&1)
1407 ch = key_menu_enter;
1408 joywait = I_GetTime() + 5;
1410 if (ev->data1&2)
1412 ch = KEY_BACKSPACE;
1413 joywait = I_GetTime() + 5;
1416 else
1418 // Process mouse input
1419 if (ev->type == ev_mouse && mousewait < I_GetTime())
1421 mousey += ev->data3;
1422 if (mousey < lasty-30)
1424 ch = KEY_DOWNARROW;
1425 mousewait = I_GetTime() + 5;
1426 mousey = lasty -= 30;
1428 else if (mousey > lasty+30)
1430 ch = KEY_UPARROW;
1431 mousewait = I_GetTime() + 5;
1432 mousey = lasty += 30;
1435 mousex += ev->data2;
1436 if (mousex < lastx-30)
1438 ch = KEY_LEFTARROW;
1439 mousewait = I_GetTime() + 5;
1440 mousex = lastx -= 30;
1442 else if (mousex > lastx+30)
1444 ch = KEY_RIGHTARROW;
1445 mousewait = I_GetTime() + 5;
1446 mousex = lastx += 30;
1449 if (ev->data1&1)
1451 ch = key_menu_enter;
1452 mousewait = I_GetTime() + 15;
1455 if (ev->data1&2)
1457 ch = KEY_BACKSPACE;
1458 mousewait = I_GetTime() + 15;
1461 else */if (ev->type == ev_keydown)
1463 ch = ev->data1;
1465 // }
1467 if (ch == -1)
1468 return false;
1471 // Save Game string input
1472 if (saveStringEnter)
1474 switch(ch)
1476 case KEY_BACKSPACE:
1477 if (saveCharIndex > 0)
1479 saveCharIndex--;
1480 savegamestrings[saveSlot][saveCharIndex] = 0;
1482 break;
1484 case KEY_ESCAPE:
1485 saveStringEnter = 0;
1486 strcpy(&savegamestrings[saveSlot][0],saveOldString);
1487 break;
1489 case KEY_ENTER:
1490 saveStringEnter = 0;
1491 if (savegamestrings[saveSlot][0])
1492 M_DoSave(saveSlot);
1493 break;
1495 default:
1496 ch = toupper(ch);
1497 if (ch != 32)
1498 if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
1499 break;
1500 if (ch >= 32 && ch <= 127 &&
1501 saveCharIndex < SAVESTRINGSIZE-1 &&
1502 M_StringWidth(savegamestrings[saveSlot]) <
1503 (SAVESTRINGSIZE-2)*8)
1505 savegamestrings[saveSlot][saveCharIndex++] = ch;
1506 savegamestrings[saveSlot][saveCharIndex] = 0;
1508 break;
1510 return true;
1513 // Take care of any messages that need input
1514 if (messageToPrint)
1516 if (messageNeedsInput == true &&
1517 !(ch == ' ' || ch == 'n' || ch == key_menu_enter || ch == key_menu_escape))
1518 return false;
1520 menuactive = messageLastMenuActive;
1521 messageToPrint = 0;
1522 if (messageRoutine)
1523 messageRoutine(ch);
1525 menuactive = false;
1526 S_StartSound(NULL,sfx_swtchx);
1527 return true;
1530 if (ch == KEY_F1) // devparm &&
1532 G_ScreenShot ();
1533 return true;
1536 // F-Keys
1537 if (!menuactive)
1539 if (ch == key_autorun) // Autorun // V
1541 autorun = !autorun;
1542 return true;
1545 switch(ch)
1548 case KEY_F1: // Help key
1549 M_StartControlPanel ();
1551 if ( gamemode == retail )
1552 currentMenu = &ReadDef2;
1553 else
1554 currentMenu = &ReadDef1;
1556 itemOn = 0;
1557 S_StartSound(NULL,sfx_swtchn);
1558 return true;
1560 case KEY_F6: // Quicksave
1561 S_StartSound(NULL,sfx_swtchn);
1562 M_QuickSave();
1563 return true;
1565 case KEY_F9: // Quickload
1566 S_StartSound(NULL,sfx_swtchn);
1567 M_QuickLoad();
1568 return true;
1574 // Pop-up menu?
1575 if (!menuactive)
1577 if (ch == key_menu_escape)
1579 M_StartControlPanel ();
1580 S_StartSound(NULL,sfx_swtchn);
1581 return true;
1583 return false;
1587 // Keys usable within menu
1588 switch (ch)
1590 case KEY_DOWNARROW:
1593 if (itemOn+1 > currentMenu->numitems-1)
1594 itemOn = 0;
1595 else
1596 itemOn++;
1597 S_StartSound(NULL,sfx_pstop);
1599 while(currentMenu->menuitems[itemOn].status==-1);
1600 return true;
1602 case KEY_UPARROW:
1605 if (!itemOn)
1606 itemOn = currentMenu->numitems-1;
1607 else
1608 itemOn--;
1609 S_StartSound(NULL,sfx_pstop);
1611 while(currentMenu->menuitems[itemOn].status==-1);
1612 return true;
1614 case KEY_LEFTARROW:
1615 if (currentMenu->menuitems[itemOn].routine &&
1616 currentMenu->menuitems[itemOn].status == 2)
1618 S_StartSound(NULL,sfx_stnmov);
1619 currentMenu->menuitems[itemOn].routine(0);
1621 return true;
1623 case KEY_RIGHTARROW:
1624 if (currentMenu->menuitems[itemOn].routine &&
1625 currentMenu->menuitems[itemOn].status == 2)
1627 S_StartSound(NULL,sfx_stnmov);
1628 currentMenu->menuitems[itemOn].routine(1);
1630 return true;
1632 case KEY_ENTER:
1633 if (currentMenu->menuitems[itemOn].routine &&
1634 currentMenu->menuitems[itemOn].status)
1636 currentMenu->lastOn = itemOn;
1637 if (currentMenu->menuitems[itemOn].status == 2)
1639 currentMenu->menuitems[itemOn].routine(1); // right arrow
1640 S_StartSound(NULL,sfx_stnmov);
1642 else
1644 currentMenu->menuitems[itemOn].routine(itemOn);
1645 S_StartSound(NULL,sfx_pistol);
1648 return true;
1650 case KEY_ESCAPE:
1651 currentMenu->lastOn = itemOn;
1652 M_ClearMenus ();
1653 S_StartSound(NULL,sfx_swtchx);
1654 return true;
1656 case KEY_BACKSPACE:
1657 currentMenu->lastOn = itemOn;
1658 if (currentMenu->prevMenu)
1660 currentMenu = currentMenu->prevMenu;
1661 itemOn = currentMenu->lastOn;
1662 S_StartSound(NULL,sfx_swtchn);
1664 return true;
1666 default:
1667 for (i = itemOn+1;i < currentMenu->numitems;i++)
1668 if (currentMenu->menuitems[i].alphaKey == ch)
1670 itemOn = i;
1671 S_StartSound(NULL,sfx_pstop);
1672 return true;
1674 for (i = 0;i <= itemOn;i++)
1675 if (currentMenu->menuitems[i].alphaKey == ch)
1677 itemOn = i;
1678 S_StartSound(NULL,sfx_pstop);
1679 return true;
1681 break;
1685 return false;
1691 // M_StartControlPanel
1693 void M_StartControlPanel (void)
1695 // intro might call this repeatedly
1696 if (menuactive)
1697 return;
1699 menuactive = 1;
1700 currentMenu = &MainDef; // JDC
1701 itemOn = currentMenu->lastOn; // JDC
1706 // M_Drawer
1707 // Called after the view has been rendered,
1708 // but before it has been blitted.
1710 void M_Drawer (void)
1712 static short x;
1713 static short y;
1714 unsigned short i;
1715 short max;
1716 char string[40];
1717 int start;
1719 inhelpscreens = false;
1722 // Horiz. & Vertically center string and print it.
1723 if (messageToPrint)
1725 start = 0;
1726 y = 100 - M_StringHeight(messageString)/2;
1727 while(*(messageString+start))
1729 for (i = 0;i < strlen(messageString+start);i++)
1730 if (*(messageString+start+i) == '\n')
1732 memset(string,0,40);
1733 strncpy(string,messageString+start,i);
1734 start += i+1;
1735 break;
1737 if (i == strlen(messageString+start))
1739 strcpy(string,messageString+start);
1740 start += i;
1743 x = 160 - M_StringWidth(string)/2;
1744 M_WriteText(x,y,string);
1745 y += SHORT(hu_font[0].height);
1747 return;
1750 if (!menuactive)
1751 return;
1753 if (currentMenu->routine)
1754 currentMenu->routine(); // call Draw routine
1756 // DRAW MENU
1757 x = currentMenu->x;
1758 y = currentMenu->y;
1759 max = currentMenu->numitems;
1761 for (i=0;i<max;i++)
1763 if (currentMenu->menuitems[i].name[0])
1764 V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name,
1765 CR_DEFAULT, VPT_STRETCH);
1766 y += LINEHEIGHT;
1769 // DRAW SKULL
1770 // CPhipps - patch drawing updated
1771 V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0,
1772 skullName[whichSkull], CR_DEFAULT, VPT_STRETCH);
1778 // M_ClearMenus
1780 void M_ClearMenus (void)
1782 menuactive = 0;
1783 // if (!netgame && usergame && paused)
1784 // sendpause = true;
1791 // M_SetupNextMenu
1793 void M_SetupNextMenu(menu_t *menudef)
1795 currentMenu = menudef;
1796 itemOn = currentMenu->lastOn;
1801 // M_Ticker
1803 void M_Ticker (void)
1805 if (--skullAnimCounter <= 0)
1807 whichSkull ^= 1;
1808 skullAnimCounter = 8;
1814 // M_Init
1816 void M_Init (void)
1818 currentMenu = &MainDef;
1819 menuactive = 0;
1820 itemOn = currentMenu->lastOn;
1821 whichSkull = 0;
1822 skullAnimCounter = 10;
1823 screenSize = screenblocks - 3;
1824 messageToPrint = 0;
1825 messageString = NULL;
1826 messageLastMenuActive = menuactive;
1827 quickSaveSlot = -1;
1829 // Here we could catch other version dependencies,
1830 // like HELP1/2, and four episodes.
1833 switch ( gamemode )
1835 case commercial:
1836 // This is used because DOOM 2 had only one HELP
1837 // page. I use CREDIT as second page now, but
1838 // kept this hack for educational purposes.
1839 MainMenu[readthis] = MainMenu[quitdoom];
1840 MainDef.numitems--;
1841 MainDef.y += 8;
1842 NewDef.prevMenu = &MainDef;
1843 ReadDef1.routine = M_DrawReadThis1;
1844 ReadDef1.x = 330;
1845 ReadDef1.y = 165;
1846 ReadMenu1[0].routine = M_FinishReadThis;
1847 break;
1848 case shareware:
1849 // Episode 2 and 3 are handled,
1850 // branching to an ad screen.
1851 case registered:
1852 // We need to remove the fourth episode.
1853 EpiDef.numitems--;
1854 break;
1855 case retail:
1856 // We are fine.
1857 default:
1858 break;