A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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.
12//
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.
17//
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).
21//
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.
24//
25// Revision 1.5 2006-04-04 23:58:37 kkurbjun
26// Make savegame strings more informative
27//
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
30//
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
33//
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.
36//
37// Revision 1.1 2006-03-28 15:44:01 dave
38// Patch #2969 - Doom! Currently only working on the H300.
39//
40//
41// DESCRIPTION:
42// DOOM selection menu, options, episode etc.
43// Sliders and icons. Kinda widget stuff.
44//
45//-----------------------------------------------------------------------------
46
47#include "doomdef.h"
48#include "dstrings.h"
49
50#include "d_main.h"
51
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"
57
58#include "r_main.h"
59#include "d_deh.h"
60#include "hu_stuff.h"
61
62#include "g_game.h"
63
64#include "m_argv.h"
65#include "m_swap.h"
66#include "s_sound.h"
67
68#include "doomstat.h"
69
70// Data.
71#include "sounds.h"
72
73#include "m_menu.h"
74#include "rockmacros.h"
75
76
77extern patchnum_t hu_font[HU_FONTSIZE];
78extern boolean message_dontfuckwithme;
79
80extern boolean chat_on; // in heads-up code
81
82//
83// defaulted values
84//
85int mouseSensitivity; // has default
86
87// Show messages has default, 0 = off, 1 = on
88int showMessages;
89
90// Blocky mode, has default, 0 = high, 1 = normal
91int screenblocks; // has default
92
93// temp for screenblocks (0-9)
94int screenSize;
95
96// -1 = no quicksave slot picked!
97int quickSaveSlot;
98
99// 1 = message to be printed
100int messageToPrint;
101// ...and here is the message string!
102const char* messageString;
103
104// message x & y
105int messx;
106int messy;
107int messageLastMenuActive;
108
109// timed message = no input from user
110boolean messageNeedsInput;
111
112void (*messageRoutine)(int response);
113
114#define SAVESTRINGSIZE 24
115
116// we are going to be entering a savegame string
117int saveStringEnter;
118int saveSlot; // which slot to save in
119int saveCharIndex; // which char we're editing
120// old save description before edit
121char saveOldString[SAVESTRINGSIZE];
122
123boolean inhelpscreens;
124boolean menuactive;
125
126#define SKULLXOFF -32
127#define LINEHEIGHT 16
128
129extern boolean sendpause;
130char savegamestrings[10][SAVESTRINGSIZE];
131
132char endstring[170];
133
134
135//
136// MENU TYPEDEFS
137//
138typedef struct
139{
140 // 0 = no cursor here, 1 = ok, 2 = arrows ok
141 short status;
142
143 char name[10];
144
145 // choice = menu item #.
146 // if status = 2,
147 // choice=0:leftarrow,1:rightarrow
148 void (*routine)(int choice);
149
150 // hotkey in menu
151 char alphaKey;
152}
153menuitem_t;
154
155
156
157typedef struct menu_s
158{
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
166}
167menu_t;
168
169short itemOn; // menu item skull is on
170short skullAnimCounter; // skull animation counter
171short whichSkull; // which skull to draw
172int systemvol;
173
174// graphic name of skulls
175// warning: initializer-string for array of chars is too long
176char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
177
178// current menudef
179menu_t* currentMenu;
180
181//
182// PROTOTYPES
183//
184void M_NewGame(int choice);
185void M_Episode(int choice);
186void M_ChooseSkill(int choice);
187void M_LoadGame(int choice);
188void M_SaveGame(int choice);
189void M_Options(int choice);
190void M_EndGame(int choice);
191void M_ReadThis(int choice);
192void M_ReadThis2(int choice);
193void M_QuitDOOM(int choice);
194
195void M_ChangeMessages(int choice);
196void M_ChangeGamma(int choice);
197void M_SfxVol(int choice);
198void M_MusicVol(int choice);
199void M_SystemVol(int choice);
200void M_SizeDisplay(int choice);
201void M_StartGame(int choice);
202void M_Sound(int choice);
203
204void M_FinishReadThis(int choice);
205void M_LoadSelect(int choice);
206void M_SaveSelect(int choice);
207void M_ReadSaveStrings(void);
208void M_QuickSave(void);
209void M_QuickLoad(void);
210
211void M_DrawMainMenu(void);
212void M_DrawReadThis1(void);
213void M_DrawReadThis2(void);
214void M_DrawNewGame(void);
215void M_DrawEpisode(void);
216void M_DrawOptions(void);
217void M_DrawSound(void);
218void M_DrawLoad(void);
219void M_DrawSave(void);
220
221void M_DrawSaveLoadBorder(int x,int y);
222void M_SetupNextMenu(menu_t *menudef);
223void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
224void M_DrawEmptyCell(menu_t *menu,int item);
225void M_DrawSelCell(menu_t *menu,int item);
226void M_WriteText(int x, int y, char *string);
227int M_StringWidth(const char* string);
228int M_StringHeight(const char* string);
229void M_StartControlPanel(void);
230void M_StartMessage(const char *string,void *routine,boolean input);
231void M_StopMessage(void);
232void M_ClearMenus (void);
233
234
235
236
237//
238// DOOM MENU
239//
240enum
241{
242 newgame = 0,
243 options,
244 loadgame,
245 savegame,
246 readthis,
247 quitdoom,
248 main_end
249};
250unsigned main_e;
251
252menuitem_t MainMenu[]=
253 {
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'}
261 };
262
263menu_t MainDef =
264 {
265 main_end,
266 NULL,
267 MainMenu,
268 M_DrawMainMenu,
269 97,64,
270 0
271 };
272
273
274//
275// EPISODE SELECT
276//
277enum
278{
279 ep1,
280 ep2,
281 ep3,
282 ep4,
283 ep_end
284};
285unsigned episodes_e;
286
287menuitem_t EpisodeMenu[]=
288 {
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'}
293 };
294
295menu_t EpiDef =
296 {
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
303 };
304
305//
306// NEW GAME
307//
308enum
309{
310 killthings,
311 toorough,
312 hurtme,
313 violence,
314 nightmare,
315 newg_end
316};
317unsigned newgame_e;
318
319menuitem_t NewGameMenu[]=
320 {
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'}
326 };
327
328menu_t NewDef =
329 {
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
336 };
337
338
339
340//
341// OPTIONS MENU
342//
343enum
344{
345 endgame,
346 messages,
347 scrnsize,
348 option_empty1,
349 gamasens,
350 option_empty2,
351 soundvol,
352 opt_end
353};
354unsigned options_e;
355
356menuitem_t OptionsMenu[]=
357 {
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'}
365 };
366
367menu_t OptionsDef =
368 {
369 opt_end,
370 &MainDef,
371 OptionsMenu,
372 M_DrawOptions,
373 60,37,
374 0
375 };
376
377//
378// Read This! MENU 1 & 2
379//
380enum
381{
382 rdthsempty1,
383 read1_end
384};
385unsigned read_e;
386
387menuitem_t ReadMenu1[] =
388 {
389 {1,"",M_ReadThis2,0}
390 };
391
392menu_t ReadDef1 =
393 {
394 read1_end,
395 &MainDef,
396 ReadMenu1,
397 M_DrawReadThis1,
398 280,185,
399 0
400 };
401
402enum
403{
404 rdthsempty2,
405 read2_end
406};
407unsigned read_e2;
408
409menuitem_t ReadMenu2[]=
410 {
411 {1,"",M_FinishReadThis,0}
412 };
413
414menu_t ReadDef2 =
415 {
416 read2_end,
417 &ReadDef1,
418 ReadMenu2,
419 M_DrawReadThis2,
420 330,175,
421 0
422 };
423
424//
425// SOUND VOLUME MENU
426//
427enum
428{
429 sfx_vol,
430 sfx_empty1,
431 music_vol,
432 sfx_empty2,
433 system_vol,
434 sfx_empty3,
435 sound_end
436};
437unsigned sound_e;
438
439menuitem_t SoundMenu[]=
440 {
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
447 };
448
449menu_t SoundDef =
450 {
451 sound_end,
452 &OptionsDef,
453 SoundMenu,
454 M_DrawSound,
455 80,64,
456 0
457 };
458
459//
460// LOAD GAME MENU
461//
462enum
463{
464 load1,
465 load2,
466 load3,
467 load4,
468 load5,
469 load6,
470 load_end
471};
472unsigned load_e;
473
474menuitem_t LoadMenu[]=
475 {
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'}
482 };
483
484menu_t LoadDef =
485 {
486 load_end,
487 &MainDef,
488 LoadMenu,
489 M_DrawLoad,
490 80,54,
491 0
492 };
493
494//
495// SAVE GAME MENU
496//
497menuitem_t SaveMenu[]=
498 {
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'}
505 };
506
507menu_t SaveDef =
508 {
509 load_end,
510 &MainDef,
511 SaveMenu,
512 M_DrawSave,
513 80,54,
514 0
515 };
516
517
518//
519// M_ReadSaveStrings
520// read the strings from the savegame files
521//
522void M_ReadSaveStrings(void)
523{
524 int handle;
525 int i;
526 char name[256];
527
528 for (i = 0;i < load_end;i++)
529 {
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);
534
535 handle = open (name, O_RDONLY | 0);
536 if (handle == -1)
537 {
538 strcpy(&savegamestrings[i][0],EMPTYSTRING);
539 LoadMenu[i].status = 0;
540 continue;
541 }
542 read (handle, &savegamestrings[i], SAVESTRINGSIZE);
543 close (handle);
544 LoadMenu[i].status = 1;
545 }
546}
547
548#define LOADGRAPHIC_Y 8
549//
550// M_LoadGame & Cie.
551//
552void M_DrawLoad(void)
553{
554 int i;
555
556 V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH);
557 for (i = 0;i < load_end; i++)
558 {
559 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
560 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
561 }
562}
563
564
565
566//
567// Draw border for the savegame description
568//
569void M_DrawSaveLoadBorder(int x,int y)
570{
571 int i;
572
573 V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH);
574 for (i = 0;i < 24;i++)
575 {
576 V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH);
577 x += 8;
578 }
579 V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH);
580}
581
582
583
584//
585// User wants to load this game
586//
587void M_LoadSelect(int choice)
588{
589 char name[256];
590
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 ();
597}
598
599//
600// Selected from DOOM menu
601//
602void M_LoadGame (int choice)
603{
604 (void)choice;
605 if (netgame)
606 {
607 M_StartMessage(LOADNET,NULL,false);
608 return;
609 }
610
611 M_SetupNextMenu(&LoadDef);
612 M_ReadSaveStrings();
613}
614
615
616//
617// M_SaveGame & Cie.
618//
619void M_DrawSave(void)
620{
621 int i;
622
623 V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH);
624 for (i = 0;i < load_end; i++)
625 {
626 M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
627 M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
628 }
629
630 if (saveStringEnter)
631 {
632 i = M_StringWidth(savegamestrings[saveSlot]);
633 M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
634 }
635}
636
637//
638// M_Responder calls this when user is finished
639//
640void M_DoSave(int slot)
641{
642 G_SaveGame (slot,savegamestrings[slot]);
643 M_ClearMenus ();
644
645 // PICK QUICKSAVE SLOT YET?
646 if (quickSaveSlot == -2)
647 quickSaveSlot = slot;
648}
649
650//
651// User wants to save. Start string input for M_Responder
652//
653void M_SaveSelect(int choice)
654{
655 // we are going to be intercepting all chars
656 saveStringEnter = 1;
657
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]);
668}
669
670//
671// Selected from DOOM menu
672//
673void M_SaveGame (int choice)
674{
675 (void)choice;
676 if (!usergame)
677 {
678 M_StartMessage(s_SAVEDEAD,NULL,false);
679 return;
680 }
681
682 if (gamestate != GS_LEVEL)
683 return;
684
685 M_SetupNextMenu(&SaveDef);
686 M_ReadSaveStrings();
687}
688
689
690
691//
692// M_QuickSave
693//
694char tempstring[80];
695
696void M_QuickSaveResponse(int ch)
697{
698 if (ch == 'y')
699 {
700 M_DoSave(quickSaveSlot);
701
702 S_StartSound(NULL,sfx_swtchx);
703
704 }
705}
706
707void M_QuickSave(void)
708{
709 if (!usergame)
710 {
711 S_StartSound(NULL,sfx_oof);
712 return;
713 }
714
715 if (gamestate != GS_LEVEL)
716 return;
717
718 if (quickSaveSlot < 0)
719 {
720 M_StartControlPanel();
721 M_ReadSaveStrings();
722 M_SetupNextMenu(&SaveDef);
723 quickSaveSlot = -2; // means to pick a slot now
724 return;
725 }
726 snprintf(tempstring,sizeof(tempstring),s_QSPROMPT,savegamestrings[quickSaveSlot]);
727 M_StartMessage(tempstring,M_QuickSaveResponse,true);
728}
729
730
731
732//
733// M_QuickLoad
734//
735void M_QuickLoadResponse(int ch)
736{
737 if (ch == 'y')
738 {
739 M_LoadSelect(quickSaveSlot);
740 S_StartSound(NULL,sfx_swtchx);
741 }
742}
743
744
745void M_QuickLoad(void)
746{
747 if (netgame)
748 {
749 M_StartMessage(QLOADNET,NULL,false);
750 return;
751 }
752
753 if (quickSaveSlot < 0)
754 {
755 M_StartMessage(QSAVESPOT,NULL,false);
756 return;
757 }
758 snprintf(tempstring, sizeof(tempstring), QLPROMPT,savegamestrings[quickSaveSlot]);
759 M_StartMessage(tempstring,M_QuickLoadResponse,true);
760}
761
762
763
764
765//
766// Read This Menus
767// Had a "quick hack to fix romero bug"
768//
769void M_DrawReadThis1(void)
770{
771 inhelpscreens = true;
772 switch ( gamemode )
773 {
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;
784 }
785 return;
786}
787
788
789
790//
791// Read This Menus - optional second page.
792//
793void M_DrawReadThis2(void)
794{
795 inhelpscreens = true;
796 switch ( gamemode )
797 {
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;
809 }
810 return;
811}
812
813
814//
815// Change Sfx & Music volumes
816//
817void M_DrawSound(void)
818{
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);
821
822 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
823 16,snd_SfxVolume);
824
825 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
826 16,snd_MusicVolume);
827
828 M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(system_vol+1),
829 16,(sysmax+systemvol)/5);
830}
831
832void M_Sound(int choice)
833{
834 (void) choice;
835 M_SetupNextMenu(&SoundDef);
836}
837
838void M_SfxVol(int choice)
839{
840 switch(choice)
841 {
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;
850 }
851
852 S_SetSfxVolume(snd_SfxVolume /* *8 */);
853}
854
855void M_MusicVol(int choice)
856{
857 switch(choice)
858 {
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;
867 }
868
869 S_SetMusicVolume(snd_MusicVolume /* *8 */);
870}
871
872void M_SystemVol(int choice)
873{
874 switch(choice)
875 {
876 case 0:
877 if (systemvol-5>rb->sound_min(SOUND_VOLUME))
878 {
879 systemvol-=5;
880 rb->sound_set(SOUND_VOLUME, systemvol);
881 }
882 break;
883 case 1:
884 if (systemvol+5<rb->sound_max(SOUND_VOLUME))
885 {
886 systemvol+=5;
887 rb->sound_set(SOUND_VOLUME, systemvol);
888 }
889 break;
890 }
891}
892
893//
894// M_DrawMainMenu
895//
896void M_DrawMainMenu(void)
897{
898 V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH);
899}
900
901
902
903
904//
905// M_NewGame
906//
907void M_DrawNewGame(void)
908{
909 // CPhipps - patch drawing updated
910 V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH);
911 V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH);
912}
913
914void M_NewGame(int choice)
915{
916 (void) choice;
917 if (netgame && !demoplayback)
918 {
919 M_StartMessage(s_NEWGAME,NULL,false);
920 return;
921 }
922
923 if ( gamemode == commercial )
924 M_SetupNextMenu(&NewDef);
925 else
926 M_SetupNextMenu(&EpiDef);
927}
928
929
930//
931// M_Episode
932//
933int epi;
934
935void M_DrawEpisode(void)
936{
937 // CPhipps - patch drawing updated
938 V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH);
939}
940
941void M_VerifyNightmare(int ch)
942{
943 if (ch != key_menu_enter)
944 return;
945
946 G_DeferedInitNew(nightmare,epi+1,1);
947 M_ClearMenus ();
948}
949
950void M_ChooseSkill(int choice)
951{
952 if (choice == nightmare)
953 {
954 M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true);
955 return;
956 }
957
958 //jff 3/24/98 remember last skill selected
959 // killough 10/98 moved to here
960 defaultskill = choice+1;
961
962 G_DeferedInitNew(choice,epi+1,1);
963 M_ClearMenus ();
964}
965
966void M_Episode(int choice)
967{
968 if ( (gamemode == shareware)
969 && choice)
970 {
971 M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized
972 M_SetupNextMenu(&ReadDef1);
973 return;
974 }
975
976 // Yet another hack...
977 if ( (gamemode == registered)
978 && (choice > 2))
979 {
980 /* Digita */
981 // fprintf( stderr,
982 // "M_Episode: 4th episode requires UltimateDOOM\n");
983 choice = 0;
984 }
985
986 epi = choice;
987 M_SetupNextMenu(&NewDef);
988}
989
990
991
992//
993// M_Options
994//
995char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
996char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
997
998
999void M_DrawOptions(void)
1000{
1001 // CPhipps - patch drawing updated
1002 V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH);
1003
1004 V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0,
1005 msgNames[showMessages], CR_DEFAULT, VPT_STRETCH);
1006
1007 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(gamasens+1),
1008 4,usegamma);
1009
1010 M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
1011 9,screenSize);
1012}
1013
1014void M_Options(int choice)
1015{
1016 (void)choice;
1017 M_SetupNextMenu(&OptionsDef);
1018}
1019
1020
1021
1022//
1023// Toggle messages on/off
1024//
1025void M_ChangeMessages(int choice)
1026{
1027 (void)choice;
1028 showMessages = 1 - showMessages;
1029
1030 if (!showMessages)
1031 players[consoleplayer].message = s_MSGOFF;
1032 else
1033 players[consoleplayer].message = s_MSGON ;
1034
1035 message_dontfuckwithme = true;
1036}
1037
1038
1039//
1040// M_EndGame
1041//
1042void M_EndGameResponse(int ch)
1043{
1044 if (ch != key_menu_enter)
1045 return;
1046
1047 // killough 5/26/98: make endgame quit if recording or playing back demo
1048 if (demorecording || singledemo)
1049 G_CheckDemoStatus();
1050
1051 currentMenu->lastOn = itemOn;
1052 M_ClearMenus ();
1053 D_StartTitle ();
1054}
1055
1056void M_EndGame(int choice)
1057{
1058 (void)choice;
1059 if (!usergame)
1060 {
1061 S_StartSound(NULL,sfx_oof);
1062 return;
1063 }
1064
1065 if (netgame)
1066 {
1067 M_StartMessage(s_NETEND,NULL,false);
1068 return;
1069 }
1070
1071 M_StartMessage(s_ENDGAME,M_EndGameResponse,true);
1072}
1073
1074
1075
1076
1077//
1078// M_ReadThis
1079//
1080void M_ReadThis(int choice)
1081{
1082 (void)choice;
1083 M_SetupNextMenu(&ReadDef1);
1084}
1085
1086void M_ReadThis2(int choice)
1087{
1088 (void)choice;
1089 M_SetupNextMenu(&ReadDef2);
1090}
1091
1092void M_FinishReadThis(int choice)
1093{
1094 (void)choice;
1095 M_SetupNextMenu(&MainDef);
1096}
1097
1098
1099
1100
1101//
1102// M_QuitDOOM
1103//
1104int quitsounds[8] =
1105 {
1106 sfx_pldeth,
1107 sfx_dmpain,
1108 sfx_popain,
1109 sfx_slop,
1110 sfx_telept,
1111 sfx_posit1,
1112 sfx_posit3,
1113 sfx_sgtatk
1114 };
1115
1116int quitsounds2[8] =
1117 {
1118 sfx_vilact,
1119 sfx_getpow,
1120 sfx_boscub,
1121 sfx_slop,
1122 sfx_skeswg,
1123 sfx_kntdth,
1124 sfx_bspact,
1125 sfx_sgtatk
1126 };
1127
1128
1129
1130void M_QuitResponse(int ch)
1131{
1132 if (ch != key_menu_enter)
1133 return;
1134 if (!netgame)
1135 {
1136 if (gamemode == commercial)
1137 S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
1138 else
1139 S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
1140 I_WaitVBL(105);
1141 }
1142 I_Quit ();
1143}
1144
1145
1146
1147
1148void M_QuitDOOM(int choice)
1149{
1150 (void)choice;
1151 // We pick index 0 which is language sensitive,
1152 // or one at random, between 1 and maximum number.
1153 if (language != english )
1154 snprintf(endstring,sizeof(endstring),"%s\n\n%s",s_DOSY, endmsg[0] );
1155 else
1156 snprintf(endstring,sizeof(endstring),"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY);
1157
1158 M_StartMessage(endstring,M_QuitResponse,true);
1159}
1160
1161
1162
1163
1164void M_ChangeGamma(int choice)
1165{
1166 switch(choice)
1167 {
1168 case 0:
1169 if (usegamma)
1170 usegamma--;
1171 break;
1172 case 1:
1173 if (usegamma < 4)
1174 usegamma++;
1175 break;
1176 }
1177 V_SetPalette (0);
1178}
1179
1180void M_SizeDisplay(int choice)
1181{
1182 switch(choice)
1183 {
1184 case 0:
1185 if (screenSize > 0)
1186 {
1187 screenblocks--;
1188 screenSize--;
1189 }
1190 break;
1191 case 1:
1192 if (screenSize < 8)
1193 {
1194 screenblocks++;
1195 screenSize++;
1196 }
1197 break;
1198 }
1199
1200
1201 R_SetViewSize (screenblocks);
1202}
1203
1204
1205
1206
1207//
1208// Menu Functions
1209//
1210void
1211M_DrawThermo
1212( int x,
1213 int y,
1214 int thermWidth,
1215 int thermDot )
1216{
1217 int xx;
1218 int i;
1219
1220 xx = x;
1221 V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH);
1222 xx += 8;
1223 for (i=0;i<thermWidth;i++)
1224 {
1225 V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
1226 xx += 8;
1227 }
1228 V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
1229 V_DrawNamePatch((x+8)+thermDot*8,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
1230}
1231
1232
1233
1234void
1235M_DrawEmptyCell
1236( menu_t* menu,
1237 int item )
1238{
1239 // CPhipps - patch drawing updated
1240 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
1241 "M_CELL1", CR_DEFAULT, VPT_STRETCH);
1242}
1243
1244void
1245M_DrawSelCell
1246( menu_t* menu,
1247 int item )
1248{
1249 // CPhipps - patch drawing updated
1250 V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
1251 "M_CELL2", CR_DEFAULT, VPT_STRETCH);
1252}
1253
1254
1255void
1256M_StartMessage
1257( const char* string,
1258 void* routine,
1259 boolean input )
1260{
1261 messageLastMenuActive = menuactive;
1262 messageToPrint = 1;
1263 messageString = string;
1264 messageRoutine = routine;
1265 messageNeedsInput = input;
1266 menuactive = true;
1267 return;
1268}
1269
1270
1271
1272void M_StopMessage(void)
1273{
1274 menuactive = messageLastMenuActive;
1275 messageToPrint = 0;
1276}
1277
1278
1279
1280//
1281// Find string width from hu_font chars
1282//
1283int M_StringWidth(const char* string)
1284{
1285 int i, c, w = 0;
1286 for (i = 0;(size_t)i < strlen(string);i++)
1287 w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ?
1288 4 : SHORT(hu_font[c].width);
1289 return w;
1290}
1291
1292//
1293// Find string height from hu_font chars
1294//
1295
1296int M_StringHeight(const char* string)
1297{
1298 int i, h, height = h = SHORT(hu_font[0].height);
1299 for (i = 0;string[i];i++) // killough 1/31/98
1300 if (string[i] == '\n')
1301 h += height;
1302 return h;
1303}
1304
1305
1306//
1307// Write a string using the hu_font
1308//
1309void
1310M_WriteText
1311( int x,
1312 int y,
1313 char* string)
1314{
1315 int w;
1316 char* ch;
1317 int c;
1318 int cx;
1319 int cy;
1320
1321
1322 ch = string;
1323 cx = x;
1324 cy = y;
1325
1326 while(1)
1327 {
1328 c = *ch++;
1329 if (!c)
1330 break;
1331 if (c == '\n')
1332 {
1333 cx = x;
1334 cy += 12;
1335 continue;
1336 }
1337
1338 c = toupper(c) - HU_FONTSTART;
1339 if (c < 0 || c>= HU_FONTSIZE)
1340 {
1341 cx += 4;
1342 continue;
1343 }
1344
1345 w = SHORT (hu_font[c].width);
1346 if (cx+w > 320)
1347 break;
1348 // proff/nicolas 09/20/98 -- changed for hi-res
1349 // CPhipps - patch drawing updated
1350 V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
1351 cx+=w;
1352 }
1353}
1354
1355
1356
1357//
1358// CONTROL PANEL
1359//
1360
1361//
1362// M_Responder
1363//
1364boolean M_Responder (event_t* ev)
1365{
1366 int ch;
1367 int i;
1368// static int joywait = 0;
1369// static int mousewait = 0;
1370// static int mousey = 0;
1371// static int lasty = 0;
1372// static int mousex = 0;
1373// static int lastx = 0;
1374
1375 ch = -1;
1376
1377 // Process joystick input
1378
1379/* if (ev->type == ev_joystick && joywait < I_GetTime())
1380 {
1381 if (ev->data3 == -1)
1382 {
1383 ch = KEY_UPARROW;
1384 joywait = I_GetTime() + 5;
1385 }
1386 else if (ev->data3 == 1)
1387 {
1388 ch = KEY_DOWNARROW;
1389 joywait = I_GetTime() + 5;
1390 }
1391
1392 if (ev->data2 == -1)
1393 {
1394 ch = KEY_LEFTARROW;
1395 joywait = I_GetTime() + 2;
1396 }
1397 else if (ev->data2 == 1)
1398 {
1399 ch = KEY_RIGHTARROW;
1400 joywait = I_GetTime() + 2;
1401 }
1402
1403 if (ev->data1&1)
1404 {
1405 ch = key_menu_enter;
1406 joywait = I_GetTime() + 5;
1407 }
1408 if (ev->data1&2)
1409 {
1410 ch = KEY_BACKSPACE;
1411 joywait = I_GetTime() + 5;
1412 }
1413 }
1414 else
1415 {
1416 // Process mouse input
1417 if (ev->type == ev_mouse && mousewait < I_GetTime())
1418 {
1419 mousey += ev->data3;
1420 if (mousey < lasty-30)
1421 {
1422 ch = KEY_DOWNARROW;
1423 mousewait = I_GetTime() + 5;
1424 mousey = lasty -= 30;
1425 }
1426 else if (mousey > lasty+30)
1427 {
1428 ch = KEY_UPARROW;
1429 mousewait = I_GetTime() + 5;
1430 mousey = lasty += 30;
1431 }
1432
1433 mousex += ev->data2;
1434 if (mousex < lastx-30)
1435 {
1436 ch = KEY_LEFTARROW;
1437 mousewait = I_GetTime() + 5;
1438 mousex = lastx -= 30;
1439 }
1440 else if (mousex > lastx+30)
1441 {
1442 ch = KEY_RIGHTARROW;
1443 mousewait = I_GetTime() + 5;
1444 mousex = lastx += 30;
1445 }
1446
1447 if (ev->data1&1)
1448 {
1449 ch = key_menu_enter;
1450 mousewait = I_GetTime() + 15;
1451 }
1452
1453 if (ev->data1&2)
1454 {
1455 ch = KEY_BACKSPACE;
1456 mousewait = I_GetTime() + 15;
1457 }
1458 }
1459 else */if (ev->type == ev_keydown)
1460 {
1461 ch = ev->data1;
1462 }
1463// }
1464
1465 if (ch == -1)
1466 return false;
1467
1468
1469 // Save Game string input
1470 if (saveStringEnter)
1471 {
1472 switch(ch)
1473 {
1474 case KEY_BACKSPACE:
1475 if (saveCharIndex > 0)
1476 {
1477 saveCharIndex--;
1478 savegamestrings[saveSlot][saveCharIndex] = 0;
1479 }
1480 break;
1481
1482 case KEY_ESCAPE:
1483 saveStringEnter = 0;
1484 strcpy(&savegamestrings[saveSlot][0],saveOldString);
1485 break;
1486
1487 case KEY_ENTER:
1488 saveStringEnter = 0;
1489 if (savegamestrings[saveSlot][0])
1490 M_DoSave(saveSlot);
1491 break;
1492
1493 default:
1494 ch = toupper(ch);
1495 if (ch != 32)
1496 if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
1497 break;
1498 if (ch >= 32 && ch <= 127 &&
1499 saveCharIndex < SAVESTRINGSIZE-1 &&
1500 M_StringWidth(savegamestrings[saveSlot]) <
1501 (SAVESTRINGSIZE-2)*8)
1502 {
1503 savegamestrings[saveSlot][saveCharIndex++] = ch;
1504 savegamestrings[saveSlot][saveCharIndex] = 0;
1505 }
1506 break;
1507 }
1508 return true;
1509 }
1510
1511 // Take care of any messages that need input
1512 if (messageToPrint)
1513 {
1514 if (messageNeedsInput == true &&
1515 !(ch == ' ' || ch == 'n' || ch == key_menu_enter || ch == key_menu_escape))
1516 return false;
1517
1518 menuactive = messageLastMenuActive;
1519 messageToPrint = 0;
1520 if (messageRoutine)
1521 messageRoutine(ch);
1522
1523 menuactive = false;
1524 S_StartSound(NULL,sfx_swtchx);
1525 return true;
1526 }
1527/*
1528 if (ch == KEY_F1) // devparm &&
1529 {
1530 G_ScreenShot ();
1531 return true;
1532 }
1533*/
1534 // F-Keys
1535 if (!menuactive)
1536 {
1537 if (ch == key_autorun) // Autorun // V
1538 {
1539 autorun = !autorun;
1540 return true;
1541 }
1542
1543 switch(ch)
1544 {
1545/*
1546 case KEY_F1: // Help key
1547 M_StartControlPanel ();
1548
1549 if ( gamemode == retail )
1550 currentMenu = &ReadDef2;
1551 else
1552 currentMenu = &ReadDef1;
1553
1554 itemOn = 0;
1555 S_StartSound(NULL,sfx_swtchn);
1556 return true;
1557
1558 case KEY_F6: // Quicksave
1559 S_StartSound(NULL,sfx_swtchn);
1560 M_QuickSave();
1561 return true;
1562
1563 case KEY_F9: // Quickload
1564 S_StartSound(NULL,sfx_swtchn);
1565 M_QuickLoad();
1566 return true;
1567*/
1568 }
1569 }
1570
1571
1572 // Pop-up menu?
1573 if (!menuactive)
1574 {
1575 if (ch == key_menu_escape)
1576 {
1577 M_StartControlPanel ();
1578 S_StartSound(NULL,sfx_swtchn);
1579 return true;
1580 }
1581 return false;
1582 }
1583
1584
1585 // Keys usable within menu
1586 switch (ch)
1587 {
1588 case KEY_DOWNARROW:
1589 do
1590 {
1591 if (itemOn+1 > currentMenu->numitems-1)
1592 itemOn = 0;
1593 else
1594 itemOn++;
1595 S_StartSound(NULL,sfx_pstop);
1596 }
1597 while(currentMenu->menuitems[itemOn].status==-1);
1598 return true;
1599
1600 case KEY_UPARROW:
1601 do
1602 {
1603 if (!itemOn)
1604 itemOn = currentMenu->numitems-1;
1605 else
1606 itemOn--;
1607 S_StartSound(NULL,sfx_pstop);
1608 }
1609 while(currentMenu->menuitems[itemOn].status==-1);
1610 return true;
1611
1612 case KEY_LEFTARROW:
1613 if (currentMenu->menuitems[itemOn].routine &&
1614 currentMenu->menuitems[itemOn].status == 2)
1615 {
1616 S_StartSound(NULL,sfx_stnmov);
1617 currentMenu->menuitems[itemOn].routine(0);
1618 }
1619 return true;
1620
1621 case KEY_RIGHTARROW:
1622 if (currentMenu->menuitems[itemOn].routine &&
1623 currentMenu->menuitems[itemOn].status == 2)
1624 {
1625 S_StartSound(NULL,sfx_stnmov);
1626 currentMenu->menuitems[itemOn].routine(1);
1627 }
1628 return true;
1629
1630 case KEY_ENTER:
1631 if (currentMenu->menuitems[itemOn].routine &&
1632 currentMenu->menuitems[itemOn].status)
1633 {
1634 currentMenu->lastOn = itemOn;
1635 if (currentMenu->menuitems[itemOn].status == 2)
1636 {
1637 currentMenu->menuitems[itemOn].routine(1); // right arrow
1638 S_StartSound(NULL,sfx_stnmov);
1639 }
1640 else
1641 {
1642 currentMenu->menuitems[itemOn].routine(itemOn);
1643 S_StartSound(NULL,sfx_pistol);
1644 }
1645 }
1646 return true;
1647
1648 case KEY_ESCAPE:
1649 currentMenu->lastOn = itemOn;
1650 M_ClearMenus ();
1651 S_StartSound(NULL,sfx_swtchx);
1652 return true;
1653
1654 case KEY_BACKSPACE:
1655 currentMenu->lastOn = itemOn;
1656 if (currentMenu->prevMenu)
1657 {
1658 currentMenu = currentMenu->prevMenu;
1659 itemOn = currentMenu->lastOn;
1660 S_StartSound(NULL,sfx_swtchn);
1661 }
1662 return true;
1663
1664 default:
1665 for (i = itemOn+1;i < currentMenu->numitems;i++)
1666 if (currentMenu->menuitems[i].alphaKey == ch)
1667 {
1668 itemOn = i;
1669 S_StartSound(NULL,sfx_pstop);
1670 return true;
1671 }
1672 for (i = 0;i <= itemOn;i++)
1673 if (currentMenu->menuitems[i].alphaKey == ch)
1674 {
1675 itemOn = i;
1676 S_StartSound(NULL,sfx_pstop);
1677 return true;
1678 }
1679 break;
1680
1681 }
1682
1683 return false;
1684}
1685
1686
1687
1688//
1689// M_StartControlPanel
1690//
1691void M_StartControlPanel (void)
1692{
1693 // intro might call this repeatedly
1694 if (menuactive)
1695 return;
1696
1697 menuactive = 1;
1698 currentMenu = &MainDef; // JDC
1699 itemOn = currentMenu->lastOn; // JDC
1700}
1701
1702
1703//
1704// M_Drawer
1705// Called after the view has been rendered,
1706// but before it has been blitted.
1707//
1708void M_Drawer (void)
1709{
1710 static short x;
1711 static short y;
1712 unsigned short i;
1713 short max;
1714 char string[40];
1715 int start;
1716
1717 inhelpscreens = false;
1718
1719
1720 // Horiz. & Vertically center string and print it.
1721 if (messageToPrint)
1722 {
1723 start = 0;
1724 y = 100 - M_StringHeight(messageString)/2;
1725 while(*(messageString+start))
1726 {
1727 for (i = 0;i < strlen(messageString+start);i++)
1728 if (*(messageString+start+i) == '\n')
1729 {
1730 memset(string,0,40);
1731 strncpy(string,messageString+start,i);
1732 start += i+1;
1733 break;
1734 }
1735 if (i == strlen(messageString+start))
1736 {
1737 strcpy(string,messageString+start);
1738 start += i;
1739 }
1740
1741 x = 160 - M_StringWidth(string)/2;
1742 M_WriteText(x,y,string);
1743 y += SHORT(hu_font[0].height);
1744 }
1745 return;
1746 }
1747
1748 if (!menuactive)
1749 return;
1750
1751 if (currentMenu->routine)
1752 currentMenu->routine(); // call Draw routine
1753
1754 // DRAW MENU
1755 x = currentMenu->x;
1756 y = currentMenu->y;
1757 max = currentMenu->numitems;
1758
1759 for (i=0;i<max;i++)
1760 {
1761 if (currentMenu->menuitems[i].name[0])
1762 V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name,
1763 CR_DEFAULT, VPT_STRETCH);
1764 y += LINEHEIGHT;
1765 }
1766
1767 // DRAW SKULL
1768 // CPhipps - patch drawing updated
1769 V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0,
1770 skullName[whichSkull], CR_DEFAULT, VPT_STRETCH);
1771
1772}
1773
1774
1775//
1776// M_ClearMenus
1777//
1778void M_ClearMenus (void)
1779{
1780 menuactive = 0;
1781 // if (!netgame && usergame && paused)
1782 // sendpause = true;
1783}
1784
1785
1786
1787
1788//
1789// M_SetupNextMenu
1790//
1791void M_SetupNextMenu(menu_t *menudef)
1792{
1793 currentMenu = menudef;
1794 itemOn = currentMenu->lastOn;
1795}
1796
1797
1798//
1799// M_Ticker
1800//
1801void M_Ticker (void)
1802{
1803 if (--skullAnimCounter <= 0)
1804 {
1805 whichSkull ^= 1;
1806 skullAnimCounter = 8;
1807 }
1808}
1809
1810
1811//
1812// M_Init
1813//
1814void M_Init (void)
1815{
1816 currentMenu = &MainDef;
1817 menuactive = 0;
1818 itemOn = currentMenu->lastOn;
1819 whichSkull = 0;
1820 skullAnimCounter = 10;
1821 screenSize = screenblocks - 3;
1822 messageToPrint = 0;
1823 messageString = NULL;
1824 messageLastMenuActive = menuactive;
1825 quickSaveSlot = -1;
1826
1827 // Here we could catch other version dependencies,
1828 // like HELP1/2, and four episodes.
1829
1830
1831 switch ( gamemode )
1832 {
1833 case commercial:
1834 // This is used because DOOM 2 had only one HELP
1835 // page. I use CREDIT as second page now, but
1836 // kept this hack for educational purposes.
1837 MainMenu[readthis] = MainMenu[quitdoom];
1838 MainDef.numitems--;
1839 MainDef.y += 8;
1840 NewDef.prevMenu = &MainDef;
1841 ReadDef1.routine = M_DrawReadThis1;
1842 ReadDef1.x = 330;
1843 ReadDef1.y = 165;
1844 ReadMenu1[0].routine = M_FinishReadThis;
1845 break;
1846 case shareware:
1847 // Episode 2 and 3 are handled,
1848 // branching to an ad screen.
1849 case registered:
1850 // We need to remove the fourth episode.
1851 EpiDef.numitems--;
1852 break;
1853 case retail:
1854 // We are fine.
1855 default:
1856 break;
1857 }
1858
1859}
1860