Subversion Repositories Kolibri OS

Rev

Rev 298 | Blame | Last modification | View Log | Download | RSS feed

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