home *** CD-ROM | disk | FTP | other *** search
/ ST-Computer Leser-CD 2000 January / LCD_01_2000.iso / games / doom / pmdoom / src / m_menu.c < prev    next >
C/C++ Source or Header  |  1999-12-17  |  36KB  |  1,905 lines

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