home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -screenplay- / otherstuff / adoomppc_src / m_menu.c < prev    next >
C/C++ Source or Header  |  1998-04-23  |  33KB  |  1,896 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.  
  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)(void); // 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)(int response),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,SAVEGAMENAME"%d.dsg",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_DrawPatchInDirect (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_DrawPatchInDirect (x-8,y+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE));
  564.     
  565.     for (i = 0;i < 24;i++)
  566.     {
  567.     V_DrawPatchInDirect (x,y+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE));
  568.     x += 8;
  569.     }
  570.  
  571.     V_DrawPatchInDirect (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,SAVEGAMENAME"%d.dsg",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_DrawPatchInDirect (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_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE));
  759.     break;
  760.       case shareware:
  761.       case registered:
  762.       case retail:
  763.     V_DrawPatchInDirect (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_DrawPatchInDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE));
  785.     break;
  786.       case shareware:
  787.       case registered:
  788.     V_DrawPatchInDirect (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_DrawPatchInDirect (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_DrawPatchInDirect (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_DrawPatchInDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE));
  870.     V_DrawPatchInDirect (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_DrawPatchInDirect (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_DrawPatchInDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE));
  954.     
  955.     V_DrawPatchInDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
  956.                W_CacheLumpName(detailNames[detailLevel],PU_CACHE));
  957.  
  958.     V_DrawPatchInDirect (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_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE));
  1194.     xx += 8;
  1195.     for (i=0;i<thermWidth;i++)
  1196.     {
  1197.     V_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERMM",PU_CACHE));
  1198.     xx += 8;
  1199.     }
  1200.     V_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERMR",PU_CACHE));
  1201.  
  1202.     V_DrawPatchInDirect ((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_DrawPatchInDirect (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_DrawPatchInDirect (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)(int response),
  1231. /*  void*        routine, */
  1232.   boolean    input )
  1233. {
  1234.     messageLastMenuActive = menuactive;
  1235.     messageToPrint = 1;
  1236.     messageString = string;
  1237.     messageRoutine = routine;
  1238.     messageNeedsInput = input;
  1239.     menuactive = true;
  1240.     return;
  1241. }
  1242.  
  1243.  
  1244.  
  1245. void M_StopMessage(void)
  1246. {
  1247.     menuactive = messageLastMenuActive;
  1248.     messageToPrint = 0;
  1249. }
  1250.  
  1251.  
  1252.  
  1253. //
  1254. // Find string width from hu_font chars
  1255. //
  1256. int M_StringWidth(char* string)
  1257. {
  1258.     int             i;
  1259.     int             w = 0;
  1260.     int             c;
  1261.     
  1262.     for (i = 0;i < strlen(string);i++)
  1263.     {
  1264.     c = toupper(string[i]) - HU_FONTSTART;
  1265.     if (c < 0 || c >= HU_FONTSIZE)
  1266.         w += 4;
  1267.     else
  1268.         w += SWAPSHORT(hu_font[c]->width);
  1269.     }
  1270.         
  1271.     return w;
  1272. }
  1273.  
  1274.  
  1275.  
  1276. //
  1277. //      Find string height from hu_font chars
  1278. //
  1279. int M_StringHeight(char* string)
  1280. {
  1281.     int             i;
  1282.     int             h;
  1283.     int             height = SWAPSHORT(hu_font[0]->height);
  1284.     
  1285.     h = height;
  1286.     for (i = 0;i < strlen(string);i++)
  1287.     if (string[i] == '\n')
  1288.         h += height;
  1289.         
  1290.     return h;
  1291. }
  1292.  
  1293.  
  1294. //
  1295. //      Write a string using the hu_font
  1296. //
  1297. void
  1298. M_WriteText
  1299. ( int        x,
  1300.   int        y,
  1301.   char*        string)
  1302. {
  1303.     int        w;
  1304.     char*    ch;
  1305.     int        c;
  1306.     int        cx;
  1307.     int        cy;
  1308.         
  1309.  
  1310.     ch = string;
  1311.     cx = x;
  1312.     cy = y;
  1313.     
  1314.     while(1)
  1315.     {
  1316.     c = *ch++;
  1317.     if (!c)
  1318.         break;
  1319.     if (c == '\n')
  1320.     {
  1321.         cx = x;
  1322.         cy += 12;
  1323.         continue;
  1324.     }
  1325.         
  1326.     c = toupper(c) - HU_FONTSTART;
  1327.     if (c < 0 || c>= HU_FONTSIZE)
  1328.     {
  1329.         cx += 4;
  1330.         continue;
  1331.     }
  1332.         
  1333.     w = SWAPSHORT(hu_font[c]->width);
  1334.     if (cx+w > SCREENWIDTH)
  1335.         break;
  1336.     V_DrawPatchInDirect(cx, cy, 0, hu_font[c]);
  1337.     cx+=w;
  1338.     }
  1339. }
  1340.  
  1341.  
  1342.  
  1343. //
  1344. // CONTROL PANEL
  1345. //
  1346.  
  1347. //
  1348. // M_Responder
  1349. //
  1350. boolean M_Responder (event_t* ev)
  1351. {
  1352.     int             ch;
  1353.     int             i;
  1354.     static  int     joywait = 0;
  1355.     static  int     mousewait = 0;
  1356.     static  int     mousey = 0;
  1357.     static  int     lasty = 0;
  1358.     static  int     mousex = 0;
  1359.     static  int     lastx = 0;
  1360.     
  1361.     ch = -1;
  1362.     
  1363.     if (ev->type == ev_joystick && joywait < I_GetTime())
  1364.     {
  1365.     if (ev->data3 == -1)
  1366.     {
  1367.         ch = KEY_UPARROW;
  1368.         joywait = I_GetTime() + 5;
  1369.     }
  1370.     else if (ev->data3 == 1)
  1371.     {
  1372.         ch = KEY_DOWNARROW;
  1373.         joywait = I_GetTime() + 5;
  1374.     }
  1375.         
  1376.     if (ev->data2 == -1)
  1377.     {
  1378.         ch = KEY_LEFTARROW;
  1379.         joywait = I_GetTime() + 2;
  1380.     }
  1381.     else if (ev->data2 == 1)
  1382.     {
  1383.         ch = KEY_RIGHTARROW;
  1384.         joywait = I_GetTime() + 2;
  1385.     }
  1386.         
  1387.     if (ev->data1&1)
  1388.     {
  1389.         ch = KEY_ENTER;
  1390.         joywait = I_GetTime() + 5;
  1391.     }
  1392.     if (ev->data1&2)
  1393.     {
  1394.         ch = KEY_BACKSPACE;
  1395.         joywait = I_GetTime() + 5;
  1396.     }
  1397.     }
  1398.     else
  1399.     {
  1400.     if (ev->type == ev_mouse && mousewait < I_GetTime())
  1401.     {
  1402.         mousey += ev->data3;
  1403.         if (mousey < lasty-30)
  1404.         {
  1405.         ch = KEY_DOWNARROW;
  1406.         mousewait = I_GetTime() + 5;
  1407.         mousey = lasty -= 30;
  1408.         }
  1409.         else if (mousey > lasty+30)
  1410.         {
  1411.         ch = KEY_UPARROW;
  1412.         mousewait = I_GetTime() + 5;
  1413.         mousey = lasty += 30;
  1414.         }
  1415.         
  1416.         mousex += ev->data2;
  1417.         if (mousex < lastx-30)
  1418.         {
  1419.         ch = KEY_LEFTARROW;
  1420.         mousewait = I_GetTime() + 5;
  1421.         mousex = lastx -= 30;
  1422.         }
  1423.         else if (mousex > lastx+30)
  1424.         {
  1425.         ch = KEY_RIGHTARROW;
  1426.         mousewait = I_GetTime() + 5;
  1427.         mousex = lastx += 30;
  1428.         }
  1429.         
  1430.         if (ev->data1&1)
  1431.         {
  1432.         ch = KEY_ENTER;
  1433.         mousewait = I_GetTime() + 15;
  1434.         }
  1435.             
  1436.         if (ev->data1&2)
  1437.         {
  1438.         ch = KEY_BACKSPACE;
  1439.         mousewait = I_GetTime() + 15;
  1440.         }
  1441.     }
  1442.     else
  1443.         if (ev->type == ev_keydown)
  1444.         {
  1445.         ch = ev->data1;
  1446.         }
  1447.     }
  1448.     
  1449.     if (ch == -1)
  1450.     return false;
  1451.  
  1452.     
  1453.     // Save Game string input
  1454.     if (saveStringEnter)
  1455.     {
  1456.     switch(ch)
  1457.     {
  1458.       case KEY_BACKSPACE:
  1459.         if (saveCharIndex > 0)
  1460.         {
  1461.         saveCharIndex--;
  1462.         savegamestrings[saveSlot][saveCharIndex] = 0;
  1463.         }
  1464.         break;
  1465.                 
  1466.       case KEY_ESCAPE:
  1467.         saveStringEnter = 0;
  1468.         strcpy(&savegamestrings[saveSlot][0],saveOldString);
  1469.         break;
  1470.                 
  1471.       case KEY_ENTER:
  1472.         saveStringEnter = 0;
  1473.         if (savegamestrings[saveSlot][0])
  1474.         M_DoSave(saveSlot);
  1475.         break;
  1476.                 
  1477.       default:
  1478.         ch = toupper(ch);
  1479.         if (ch != 32)
  1480.         if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
  1481.             break;
  1482.         if (ch >= 32 && ch <= 127 &&
  1483.         saveCharIndex < SAVESTRINGSIZE-1 &&
  1484.         M_StringWidth(savegamestrings[saveSlot]) <
  1485.         (SAVESTRINGSIZE-2)*8)
  1486.         {
  1487.         savegamestrings[saveSlot][saveCharIndex++] = ch;
  1488.         savegamestrings[saveSlot][saveCharIndex] = 0;
  1489.         }
  1490.         break;
  1491.     }
  1492.     return true;
  1493.     }
  1494.     
  1495.     // Take care of any messages that need input
  1496.     if (messageToPrint)
  1497.     {
  1498.     if (messageNeedsInput == true &&
  1499.         !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE))
  1500.         return false;
  1501.         
  1502.     menuactive = messageLastMenuActive;
  1503.     messageToPrint = 0;
  1504.     if (messageRoutine)
  1505.         messageRoutine(ch);
  1506.             
  1507.     menuactive = false;
  1508.     S_StartSound(NULL,sfx_swtchx);
  1509.     return true;
  1510.     }
  1511.     
  1512.     if (devparm && ch == KEY_F1)
  1513.     {
  1514.     G_ScreenShot ();
  1515.     return true;
  1516.     }
  1517.         
  1518.     
  1519.     // F-Keys
  1520.     if (!menuactive)
  1521.     switch(ch)
  1522.     {
  1523.       case KEY_MINUS:         // Screen size down
  1524.         if (automapactive || chat_on)
  1525.         return false;
  1526.         M_SizeDisplay(0);
  1527.         S_StartSound(NULL,sfx_stnmov);
  1528.         return true;
  1529.                 
  1530.       case KEY_EQUALS:        // Screen size up
  1531.         if (automapactive || chat_on)
  1532.         return false;
  1533.         M_SizeDisplay(1);
  1534.         S_StartSound(NULL,sfx_stnmov);
  1535.         return true;
  1536.                 
  1537.       case KEY_F1:            // Help key
  1538.         M_StartControlPanel ();
  1539.  
  1540.         if ( gamemode == retail )
  1541.           currentMenu = &ReadDef2;
  1542.         else
  1543.           currentMenu = &ReadDef1;
  1544.         
  1545.         itemOn = 0;
  1546.         S_StartSound(NULL,sfx_swtchn);
  1547.         return true;
  1548.                 
  1549.       case KEY_F2:            // Save
  1550.         M_StartControlPanel();
  1551.         S_StartSound(NULL,sfx_swtchn);
  1552.         M_SaveGame(0);
  1553.         return true;
  1554.                 
  1555.       case KEY_F3:            // Load
  1556.         M_StartControlPanel();
  1557.         S_StartSound(NULL,sfx_swtchn);
  1558.         M_LoadGame(0);
  1559.         return true;
  1560.                 
  1561.       case KEY_F4:            // Sound Volume
  1562.         M_StartControlPanel ();
  1563.         currentMenu = &SoundDef;
  1564.         itemOn = sfx_vol;
  1565.         S_StartSound(NULL,sfx_swtchn);
  1566.         return true;
  1567.                 
  1568.       case KEY_F5:            // Detail toggle
  1569.         M_ChangeDetail(0);
  1570.         S_StartSound(NULL,sfx_swtchn);
  1571.         return true;
  1572.                 
  1573.       case KEY_F6:            // Quicksave
  1574.         S_StartSound(NULL,sfx_swtchn);
  1575.         M_QuickSave();
  1576.         return true;
  1577.                 
  1578.       case KEY_F7:            // End game
  1579.         S_StartSound(NULL,sfx_swtchn);
  1580.         M_EndGame(0);
  1581.         return true;
  1582.                 
  1583.       case KEY_F8:            // Toggle messages
  1584.         M_ChangeMessages(0);
  1585.         S_StartSound(NULL,sfx_swtchn);
  1586.         return true;
  1587.                 
  1588.       case KEY_F9:            // Quickload
  1589.         S_StartSound(NULL,sfx_swtchn);
  1590.         M_QuickLoad();
  1591.         return true;
  1592.                 
  1593.       case KEY_F10:           // Quit DOOM
  1594.         S_StartSound(NULL,sfx_swtchn);
  1595.         M_QuitDOOM(0);
  1596.         return true;
  1597.                 
  1598.       case KEY_F11:           // gamma toggle
  1599.         usegamma++;
  1600.         if (usegamma > 4)
  1601.         usegamma = 0;
  1602.         players[consoleplayer].message = gammamsg[usegamma];
  1603.         I_RecalcPalettes ();
  1604.         I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE), 0);
  1605.         return true;
  1606.                 
  1607.     }
  1608.  
  1609.     
  1610.     // Pop-up menu?
  1611.     if (!menuactive)
  1612.     {
  1613.     if (ch == KEY_ESCAPE)
  1614.     {
  1615.         M_StartControlPanel ();
  1616.         S_StartSound(NULL,sfx_swtchn);
  1617.         return true;
  1618.     }
  1619.     return false;
  1620.     }
  1621.  
  1622.     
  1623.     // Keys usable within menu
  1624.     switch (ch)
  1625.     {
  1626.       case KEY_DOWNARROW:
  1627.     do
  1628.     {
  1629.         if (itemOn+1 > currentMenu->numitems-1)
  1630.         itemOn = 0;
  1631.         else itemOn++;
  1632.         S_StartSound(NULL,sfx_pstop);
  1633.     } while(currentMenu->menuitems[itemOn].status==-1);
  1634.     return true;
  1635.         
  1636.       case KEY_UPARROW:
  1637.     do
  1638.     {
  1639.         if (!itemOn)
  1640.         itemOn = currentMenu->numitems-1;
  1641.         else itemOn--;
  1642.         S_StartSound(NULL,sfx_pstop);
  1643.     } while(currentMenu->menuitems[itemOn].status==-1);
  1644.     return true;
  1645.  
  1646.       case KEY_LEFTARROW:
  1647.     if (currentMenu->menuitems[itemOn].routine &&
  1648.         currentMenu->menuitems[itemOn].status == 2)
  1649.     {
  1650.         S_StartSound(NULL,sfx_stnmov);
  1651.         currentMenu->menuitems[itemOn].routine(0);
  1652.     }
  1653.     return true;
  1654.         
  1655.       case KEY_RIGHTARROW:
  1656.     if (currentMenu->menuitems[itemOn].routine &&
  1657.         currentMenu->menuitems[itemOn].status == 2)
  1658.     {
  1659.         S_StartSound(NULL,sfx_stnmov);
  1660.         currentMenu->menuitems[itemOn].routine(1);
  1661.     }
  1662.     return true;
  1663.  
  1664.       case KEY_ENTER:
  1665.     if (currentMenu->menuitems[itemOn].routine &&
  1666.         currentMenu->menuitems[itemOn].status)
  1667.     {
  1668.         currentMenu->lastOn = itemOn;
  1669.         if (currentMenu->menuitems[itemOn].status == 2)
  1670.         {
  1671.         currentMenu->menuitems[itemOn].routine(1);      // right arrow
  1672.         S_StartSound(NULL,sfx_stnmov);
  1673.         }
  1674.         else
  1675.         {
  1676.         currentMenu->menuitems[itemOn].routine(itemOn);
  1677.         S_StartSound(NULL,sfx_pistol);
  1678.         }
  1679.     }
  1680.     return true;
  1681.         
  1682.       case KEY_ESCAPE:
  1683.     currentMenu->lastOn = itemOn;
  1684.     M_ClearMenus ();
  1685.     S_StartSound(NULL,sfx_swtchx);
  1686.     return true;
  1687.         
  1688.       case KEY_BACKSPACE:
  1689.     currentMenu->lastOn = itemOn;
  1690.     if (currentMenu->prevMenu)
  1691.     {
  1692.         currentMenu = currentMenu->prevMenu;
  1693.         itemOn = currentMenu->lastOn;
  1694.         S_StartSound(NULL,sfx_swtchn);
  1695.     }
  1696.     return true;
  1697.     
  1698.       default:
  1699.     for (i = itemOn+1;i < currentMenu->numitems;i++)
  1700.         if (currentMenu->menuitems[i].alphaKey == ch)
  1701.         {
  1702.         itemOn = i;
  1703.         S_StartSound(NULL,sfx_pstop);
  1704.         return true;
  1705.         }
  1706.     for (i = 0;i <= itemOn;i++)
  1707.         if (currentMenu->menuitems[i].alphaKey == ch)
  1708.         {
  1709.         itemOn = i;
  1710.         S_StartSound(NULL,sfx_pstop);
  1711.         return true;
  1712.         }
  1713.     break;
  1714.     
  1715.     }
  1716.  
  1717.     return false;
  1718. }
  1719.  
  1720.  
  1721.  
  1722. //
  1723. // M_StartControlPanel
  1724. //
  1725. void M_StartControlPanel (void)
  1726. {
  1727.     // intro might call this repeatedly
  1728.     if (menuactive)
  1729.     return;
  1730.     
  1731.     menuactive = 1;
  1732.     currentMenu = &MainDef;         // JDC
  1733.     itemOn = currentMenu->lastOn;   // JDC
  1734. }
  1735.  
  1736.  
  1737. //
  1738. // M_Drawer
  1739. // Called after the view has been rendered,
  1740. // but before it has been blitted.
  1741. //
  1742. void M_Drawer (void)
  1743. {
  1744.     static short    x;
  1745.     static short    y;
  1746.     short        i;
  1747.     short        max;
  1748.     char        string[40];
  1749.     int            start;
  1750.  
  1751.     inhelpscreens = false;
  1752.  
  1753.     
  1754.     // Horiz. & Vertically center string and print it.
  1755.     if (messageToPrint)
  1756.     {
  1757.     start = 0;
  1758.     y = 100 - M_StringHeight(messageString)/2;
  1759.     while(*(messageString+start))
  1760.     {
  1761.         for (i = 0;i < strlen(messageString+start);i++)
  1762.         if (*(messageString+start+i) == '\n')
  1763.         {
  1764.             memset(string,0,40);
  1765.             strncpy(string,messageString+start,i);
  1766.             start += i+1;
  1767.             break;
  1768.         }
  1769.                 
  1770.         if (i == strlen(messageString+start))
  1771.         {
  1772.         strcpy(string,messageString+start);
  1773.         start += i;
  1774.         }
  1775.                 
  1776.         x = 160 - M_StringWidth(string)/2;
  1777.         M_WriteText(x,y,string);
  1778.         y += SWAPSHORT(hu_font[0]->height);
  1779.     }
  1780.     return;
  1781.     }
  1782.  
  1783.     if (!menuactive)
  1784.     return;
  1785.  
  1786.     if (currentMenu->routine)
  1787.     currentMenu->routine();         // call Draw routine
  1788.     
  1789.     // DRAW MENU
  1790.     x = currentMenu->x;
  1791.     y = currentMenu->y;
  1792.     max = currentMenu->numitems;
  1793.  
  1794.     for (i=0;i<max;i++)
  1795.     {
  1796.     if (currentMenu->menuitems[i].name[0])
  1797.         V_DrawPatchInDirect (x,y,0,
  1798.                    W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE));
  1799.     y += LINEHEIGHT;
  1800.     }
  1801.  
  1802.     
  1803.     // DRAW SKULL
  1804.     V_DrawPatchInDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
  1805.               W_CacheLumpName(skullName[whichSkull],PU_CACHE));
  1806.  
  1807. }
  1808.  
  1809.  
  1810. //
  1811. // M_ClearMenus
  1812. //
  1813. void M_ClearMenus (void)
  1814. {
  1815.     menuactive = 0;
  1816.     // if (!netgame && usergame && paused)
  1817.     //       sendpause = true;
  1818. }
  1819.  
  1820.  
  1821.  
  1822.  
  1823. //
  1824. // M_SetupNextMenu
  1825. //
  1826. void M_SetupNextMenu(menu_t *menudef)
  1827. {
  1828.     currentMenu = menudef;
  1829.     itemOn = currentMenu->lastOn;
  1830. }
  1831.  
  1832.  
  1833. //
  1834. // M_Ticker
  1835. //
  1836. void M_Ticker (void)
  1837. {
  1838.     if (--skullAnimCounter <= 0)
  1839.     {
  1840.     whichSkull ^= 1;
  1841.     skullAnimCounter = 8;
  1842.     }
  1843. }
  1844.  
  1845.  
  1846. //
  1847. // M_Init
  1848. //
  1849. void M_Init (void)
  1850. {
  1851.     currentMenu = &MainDef;
  1852.     menuactive = 0;
  1853.     itemOn = currentMenu->lastOn;
  1854.     whichSkull = 0;
  1855.     skullAnimCounter = 10;
  1856.     screenSize = screenblocks - 3;
  1857.     messageToPrint = 0;
  1858.     messageString = NULL;
  1859.     messageLastMenuActive = menuactive;
  1860.     quickSaveSlot = -1;
  1861.  
  1862.     // Here we could catch other version dependencies,
  1863.     //  like HELP1/2, and four episodes.
  1864.  
  1865.   
  1866.     switch ( gamemode )
  1867.     {
  1868.       case commercial:
  1869.     // This is used because DOOM 2 had only one HELP
  1870.         //  page. I use CREDIT as second page now, but
  1871.     //  kept this hack for educational purposes.
  1872.     MainMenu[readthis] = MainMenu[quitdoom];
  1873.     MainDef.numitems--;
  1874.     MainDef.y += 8;
  1875.     NewDef.prevMenu = &MainDef;
  1876.     ReadDef1.routine = M_DrawReadThis1;
  1877.     ReadDef1.x = 330;
  1878.     ReadDef1.y = 165;
  1879.     ReadMenu1[0].routine = M_FinishReadThis;
  1880.     break;
  1881.       case shareware:
  1882.     // Episode 2 and 3 are handled,
  1883.     //  branching to an ad screen.
  1884.       case registered:
  1885.     // We need to remove the fourth episode.
  1886.     EpiDef.numitems--;
  1887.     break;
  1888.       case retail:
  1889.     // We are fine.
  1890.       default:
  1891.     break;
  1892.     }
  1893.     
  1894. }
  1895.  
  1896.