Subversion Repositories Kolibri OS

Rev

Rev 300 | Go to most recent revision | 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,"doomsav%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\\doomsav%d.dsg",choice);
  577. //    else
  578.         sprintf(name,"doomsav%d.dsg",choice);
  579.  
  580.     G_LoadGame (name);
  581.     M_ClearMenus ();
  582. }
  583.  
  584. //
  585. // Selected from DOOM menu
  586. //
  587. void M_LoadGame (int choice)
  588. {
  589.     if (netgame)
  590.     {
  591.         M_StartMessage(LOADNET,NULL,false);
  592.         return;
  593.     }
  594.        
  595.     M_SetupNextMenu(&LoadDef);
  596.     M_ReadSaveStrings();
  597. }
  598.  
  599.  
  600. //
  601. //  M_SaveGame & Cie.
  602. //
  603. void M_DrawSave(void)
  604. {
  605.     int             i;
  606.        
  607.     V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE));
  608.     for (i = 0;i < load_end; i++)
  609.     {
  610.         M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
  611.         M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
  612.     }
  613.        
  614.     if (saveStringEnter)
  615.     {
  616.         i = M_StringWidth(savegamestrings[saveSlot]);
  617.         M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
  618.     }
  619. }
  620.  
  621. //
  622. // M_Responder calls this when user is finished
  623. //
  624. void M_DoSave(int slot)
  625. {
  626.  
  627.     G_SaveGame (slot,savegamestrings[slot]);
  628.     M_ClearMenus ();
  629.  
  630.     // PICK QUICKSAVE SLOT YET?
  631.     if (quickSaveSlot == -2)
  632.         quickSaveSlot = slot;
  633. }
  634.  
  635. //
  636. // User wants to save. Start string input for M_Responder
  637. //
  638. void M_SaveSelect(int choice)
  639. {
  640.     // we are going to be intercepting all chars
  641.     saveStringEnter = 1;
  642.    
  643.     saveSlot = choice;
  644.     strcpy(saveOldString,savegamestrings[choice]);
  645.     if (!strcmp(savegamestrings[choice],EMPTYSTRING))
  646.         savegamestrings[choice][0] = 0;
  647.     saveCharIndex = strlen(savegamestrings[choice]);
  648. }
  649.  
  650. //
  651. // Selected from DOOM menu
  652. //
  653. void M_SaveGame (int choice)
  654. {
  655.     if (!usergame)
  656.     {
  657.         M_StartMessage(SAVEDEAD,NULL,false);
  658.         return;
  659.     }
  660.        
  661.     if (gamestate != GS_LEVEL)
  662.         return;
  663.        
  664.     M_SetupNextMenu(&SaveDef);
  665.     M_ReadSaveStrings();
  666. }
  667.  
  668.  
  669.  
  670. //
  671. //      M_QuickSave
  672. //
  673. char    tempstring[80];
  674.  
  675. void M_QuickSaveResponse(int ch)
  676. {
  677.     if (ch == 'y')
  678.     {
  679.         M_DoSave(quickSaveSlot);
  680.         S_StartSound(NULL,sfx_swtchx);
  681.     }
  682. }
  683.  
  684. void M_QuickSave(void)
  685. {
  686.     if (!usergame)
  687.     {
  688.         S_StartSound(NULL,sfx_oof);
  689.         return;
  690.     }
  691.  
  692.     if (gamestate != GS_LEVEL)
  693.         return;
  694.        
  695.     if (quickSaveSlot < 0)
  696.     {
  697.         M_StartControlPanel();
  698.         M_ReadSaveStrings();
  699.         M_SetupNextMenu(&SaveDef);
  700.         quickSaveSlot = -2;     // means to pick a slot now
  701.         return;
  702.     }
  703.     sprintf(tempstring,QSPROMPT,savegamestrings[quickSaveSlot]);
  704.     M_StartMessage(tempstring,M_QuickSaveResponse,true);
  705. }
  706.  
  707.  
  708.  
  709. //
  710. // M_QuickLoad
  711. //
  712. void M_QuickLoadResponse(int ch)
  713. {
  714.     if (ch == 'y')
  715.     {
  716.         M_LoadSelect(quickSaveSlot);
  717.         S_StartSound(NULL,sfx_swtchx);
  718.     }
  719. }
  720.  
  721.  
  722. void M_QuickLoad(void)
  723. {
  724.     if (netgame)
  725.     {
  726.         M_StartMessage(QLOADNET,NULL,false);
  727.         return;
  728.     }
  729.        
  730.     if (quickSaveSlot < 0)
  731.     {
  732.         M_StartMessage(QSAVESPOT,NULL,false);
  733.         return;
  734.     }
  735.     sprintf(tempstring,QLPROMPT,savegamestrings[quickSaveSlot]);
  736.     M_StartMessage(tempstring,M_QuickLoadResponse,true);
  737. }
  738.  
  739.  
  740.  
  741.  
  742. //
  743. // Read This Menus
  744. // Had a "quick hack to fix romero bug"
  745. //
  746. void M_DrawReadThis1(void)
  747. {
  748.     inhelpscreens = true;
  749.     switch ( gamemode )
  750.     {
  751.       case commercial:
  752.         V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE));
  753.         break;
  754.       case shareware:
  755.       case registered:
  756.       case retail:
  757.         V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE));
  758.         break;
  759.       default:
  760.         break;
  761.     }
  762.     return;
  763. }
  764.  
  765.  
  766.  
  767. //
  768. // Read This Menus - optional second page.
  769. //
  770. void M_DrawReadThis2(void)
  771. {
  772.     inhelpscreens = true;
  773.     switch ( gamemode )
  774.     {
  775.       case retail:
  776.       case commercial:
  777.         // This hack keeps us from having to change menus.
  778.         V_DrawPatchDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE));
  779.         break;
  780.       case shareware:
  781.       case registered:
  782.         V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE));
  783.         break;
  784.       default:
  785.         break;
  786.     }
  787.     return;
  788. }
  789.  
  790.  
  791. //
  792. // Change Sfx & Music volumes
  793. //
  794. void M_DrawSound(void)
  795. {
  796.     V_DrawPatchDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE));
  797.  
  798.     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
  799.                  16,snd_SfxVolume);
  800.  
  801.     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
  802.                  16,snd_MusicVolume);
  803. }
  804.  
  805. void M_Sound(int choice)
  806. {
  807.     M_SetupNextMenu(&SoundDef);
  808. }
  809.  
  810. void M_SfxVol(int choice)
  811. {
  812.     switch(choice)
  813.     {
  814.       case 0:
  815.         if (snd_SfxVolume)
  816.             snd_SfxVolume--;
  817.         break;
  818.       case 1:
  819.         if (snd_SfxVolume < 15)
  820.             snd_SfxVolume++;
  821.         break;
  822.     }
  823.        
  824.     S_SetSfxVolume(snd_SfxVolume /* *8 */);
  825. }
  826.  
  827. void M_MusicVol(int choice)
  828. {
  829.     switch(choice)
  830.     {
  831.       case 0:
  832.         if (snd_MusicVolume)
  833.             snd_MusicVolume--;
  834.         break;
  835.       case 1:
  836.         if (snd_MusicVolume < 15)
  837.             snd_MusicVolume++;
  838.         break;
  839.     }
  840.        
  841.     S_SetMusicVolume(snd_MusicVolume /* *8 */);
  842. }
  843.  
  844.  
  845.  
  846.  
  847. //
  848. // M_DrawMainMenu
  849. //
  850. void M_DrawMainMenu(void)
  851. {
  852.     V_DrawPatchDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE));
  853. }
  854.  
  855.  
  856.  
  857.  
  858. //
  859. // M_NewGame
  860. //
  861. void M_DrawNewGame(void)
  862. {
  863.     V_DrawPatchDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE));
  864.     V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE));
  865. }
  866.  
  867. void M_NewGame(int choice)
  868. {
  869.     if (netgame && !demoplayback)
  870.     {
  871.         M_StartMessage(NEWGAME,NULL,false);
  872.         return;
  873.     }
  874.        
  875.     if ( gamemode == commercial )
  876.         M_SetupNextMenu(&NewDef);
  877.     else
  878.         M_SetupNextMenu(&EpiDef);
  879. }
  880.  
  881.  
  882. //
  883. //      M_Episode
  884. //
  885. int     epi;
  886.  
  887. void M_DrawEpisode(void)
  888. {
  889.     V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE));
  890. }
  891.  
  892. void M_VerifyNightmare(int ch)
  893. {
  894.     if (ch != 'y')
  895.         return;
  896.                
  897.     G_DeferedInitNew(nightmare,epi+1,1);
  898.     M_ClearMenus ();
  899. }
  900.  
  901. void M_ChooseSkill(int choice)
  902. {
  903.     if (choice == nightmare)
  904.     {
  905.         M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
  906.         return;
  907.     }
  908.        
  909.     G_DeferedInitNew(choice,epi+1,1);
  910.     M_ClearMenus ();
  911. }
  912.  
  913. void M_Episode(int choice)
  914. {
  915.     if ( (gamemode == shareware)
  916.          && choice)
  917.     {
  918.         M_StartMessage(SWSTRING,NULL,false);
  919.         M_SetupNextMenu(&ReadDef1);
  920.         return;
  921.     }
  922.  
  923.     // Yet another hack...
  924.     if ( (gamemode == registered)
  925.          && (choice > 2))
  926.     {
  927.  //     __libclog_printf("M_Episode: 4th episode requires UltimateDOOM\n");
  928.       choice = 0;
  929.     }
  930.          
  931.     epi = choice;
  932.     M_SetupNextMenu(&NewDef);
  933. }
  934.  
  935.  
  936.  
  937. //
  938. // M_Options
  939. //
  940. char    detailNames[2][9]       = {"M_GDHIGH","M_GDLOW"};
  941. char    msgNames[2][9]          = {"M_MSGOFF","M_MSGON"};
  942.  
  943.  
  944. void M_DrawOptions(void)
  945. {
  946.     V_DrawPatchDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE));
  947.        
  948.     V_DrawPatchDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
  949.                        W_CacheLumpName(detailNames[detailLevel],PU_CACHE));
  950.  
  951.     V_DrawPatchDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0,
  952.                        W_CacheLumpName(msgNames[showMessages],PU_CACHE));
  953.  
  954.     M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
  955.                  10,mouseSensitivity);
  956.        
  957.     M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
  958.                  9,screenSize);
  959. }
  960.  
  961. void M_Options(int choice)
  962. {
  963.     M_SetupNextMenu(&OptionsDef);
  964. }
  965.  
  966.  
  967.  
  968. //
  969. //      Toggle messages on/off
  970. //
  971. void M_ChangeMessages(int choice)
  972. {
  973.     // warning: unused parameter `int choice'
  974.     choice = 0;
  975.     showMessages = 1 - showMessages;
  976.        
  977.     if (!showMessages)
  978.         players[consoleplayer].message = MSGOFF;
  979.     else
  980.         players[consoleplayer].message = MSGON ;
  981.  
  982.     message_dontfuckwithme = true;
  983. }
  984.  
  985.  
  986. //
  987. // M_EndGame
  988. //
  989. void M_EndGameResponse(int ch)
  990. {
  991.     if (ch != 'y')
  992.         return;
  993.                
  994.     currentMenu->lastOn = itemOn;
  995.     M_ClearMenus ();
  996.     D_StartTitle ();
  997. }
  998.  
  999. void M_EndGame(int choice)
  1000. {
  1001.     choice = 0;
  1002.     if (!usergame)
  1003.     {
  1004.         S_StartSound(NULL,sfx_oof);
  1005.         return;
  1006.     }
  1007.        
  1008.     if (netgame)
  1009.     {
  1010.         M_StartMessage(NETEND,NULL,false);
  1011.         return;
  1012.     }
  1013.        
  1014.     M_StartMessage(ENDGAME,M_EndGameResponse,true);
  1015. }
  1016.  
  1017.  
  1018.  
  1019.  
  1020. //
  1021. // M_ReadThis
  1022. //
  1023. void M_ReadThis(int choice)
  1024. {
  1025.     choice = 0;
  1026.     M_SetupNextMenu(&ReadDef1);
  1027. }
  1028.  
  1029. void M_ReadThis2(int choice)
  1030. {
  1031.     choice = 0;
  1032.     M_SetupNextMenu(&ReadDef2);
  1033. }
  1034.  
  1035. void M_FinishReadThis(int choice)
  1036. {
  1037.     choice = 0;
  1038.     M_SetupNextMenu(&MainDef);
  1039. }
  1040.  
  1041.  
  1042.  
  1043.  
  1044. //
  1045. // M_QuitDOOM
  1046. //
  1047. int     quitsounds[8] =
  1048. {
  1049.     sfx_pldeth,
  1050.     sfx_dmpain,
  1051.     sfx_popain,
  1052.     sfx_slop,
  1053.     sfx_telept,
  1054.     sfx_posit1,
  1055.     sfx_posit3,
  1056.     sfx_sgtatk
  1057. };
  1058.  
  1059. int     quitsounds2[8] =
  1060. {
  1061.     sfx_vilact,
  1062.     sfx_getpow,
  1063.     sfx_boscub,
  1064.     sfx_slop,
  1065.     sfx_skeswg,
  1066.     sfx_kntdth,
  1067.     sfx_bspact,
  1068.     sfx_sgtatk
  1069. };
  1070.  
  1071.  
  1072.  
  1073. void M_QuitResponse(int ch)
  1074. {
  1075.     if (ch != 'y')
  1076.         return;
  1077.     if (!netgame)
  1078.     {
  1079.         if (gamemode == commercial)
  1080.             S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
  1081.         else
  1082.             S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
  1083.         I_WaitVBL(105);
  1084.     }
  1085.     I_Quit ();
  1086. }
  1087.  
  1088.  
  1089.  
  1090.  
  1091. void M_QuitDOOM(int choice)
  1092. {
  1093.   // We pick index 0 which is language sensitive,
  1094.   //  or one at random, between 1 and maximum number.
  1095.   if (language != english )
  1096.     sprintf(endstring,"%s\n\n"DOSY, endmsg[0] );
  1097.   else
  1098.     sprintf(endstring,"%s\n\n"DOSY, endmsg[ (gametic%(NUM_QUITMESSAGES-2))+1 ]);
  1099.  
  1100.   M_StartMessage(endstring,M_QuitResponse,true);
  1101. }
  1102.  
  1103.  
  1104.  
  1105. void M_ChangeSensitivity(int choice)
  1106. {
  1107.     switch(choice)
  1108.     {
  1109.       case 0:
  1110.         if (mouseSensitivity)
  1111.             mouseSensitivity--;
  1112.         break;
  1113.       case 1:
  1114.         if (mouseSensitivity < 9)
  1115.             mouseSensitivity++;
  1116.         break;
  1117.     }
  1118. }
  1119.  
  1120.  
  1121.  
  1122.  
  1123. void M_ChangeDetail(int choice)
  1124. {
  1125.     choice = 0;
  1126.     detailLevel = 1 - detailLevel;
  1127.  
  1128.     // FIXME - does not work. Remove anyway?
  1129. //    __libclog_printf("M_ChangeDetail: low detail mode n.a.\n");
  1130.  
  1131.     return;
  1132.    
  1133.     /*R_SetViewSize (screenblocks, detailLevel);
  1134.  
  1135.     if (!detailLevel)
  1136.         players[consoleplayer].message = DETAILHI;
  1137.     else
  1138.         players[consoleplayer].message = DETAILLO;*/
  1139. }
  1140.  
  1141.  
  1142.  
  1143.  
  1144. void M_SizeDisplay(int choice)
  1145. {
  1146.     switch(choice)
  1147.     {
  1148.       case 0:
  1149.         if (screenSize > 0)
  1150.         {
  1151.             screenblocks--;
  1152.             screenSize--;
  1153.         }
  1154.         break;
  1155.       case 1:
  1156.         if (screenSize < 8)
  1157.         {
  1158.             screenblocks++;
  1159.             screenSize++;
  1160.         }
  1161.         break;
  1162.     }
  1163.        
  1164.  
  1165.     R_SetViewSize (screenblocks, detailLevel);
  1166. }
  1167.  
  1168.  
  1169.  
  1170.  
  1171. //
  1172. //      Menu Functions
  1173. //
  1174. void
  1175. M_DrawThermo
  1176. ( int   x,
  1177.   int   y,
  1178.   int   thermWidth,
  1179.   int   thermDot )
  1180. {
  1181.     int         xx;
  1182.     int         i;
  1183.  
  1184.     xx = x;
  1185.     V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE));
  1186.     xx += 8;
  1187.     for (i=0;i<thermWidth;i++)
  1188.     {
  1189.         V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMM",PU_CACHE));
  1190.         xx += 8;
  1191.     }
  1192.     V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMR",PU_CACHE));
  1193.  
  1194.     V_DrawPatchDirect ((x+8) + thermDot*8,y,
  1195.                        0,W_CacheLumpName("M_THERMO",PU_CACHE));
  1196. }
  1197.  
  1198.  
  1199.  
  1200. void
  1201. M_DrawEmptyCell
  1202. ( menu_t*       menu,
  1203.   int           item )
  1204. {
  1205.     V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
  1206.                        W_CacheLumpName("M_CELL1",PU_CACHE));
  1207. }
  1208.  
  1209. void
  1210. M_DrawSelCell
  1211. ( menu_t*       menu,
  1212.   int           item )
  1213. {
  1214.     V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
  1215.                        W_CacheLumpName("M_CELL2",PU_CACHE));
  1216. }
  1217.  
  1218.  
  1219. void
  1220. M_StartMessage
  1221. ( char*         string,
  1222.   void*         routine,
  1223.   boolean       input )
  1224. {
  1225.     messageLastMenuActive = menuactive;
  1226.     messageToPrint = 1;
  1227.     messageString = string;
  1228.     messageRoutine = routine;
  1229.     messageNeedsInput = input;
  1230.     menuactive = true;
  1231.     return;
  1232. }
  1233.  
  1234.  
  1235.  
  1236. void M_StopMessage(void)
  1237. {
  1238.     menuactive = messageLastMenuActive;
  1239.     messageToPrint = 0;
  1240. }
  1241.  
  1242.  
  1243.  
  1244. //
  1245. // Find string width from hu_font chars
  1246. //
  1247. int M_StringWidth(char* string)
  1248. {
  1249.     int             i;
  1250.     int             w = 0;
  1251.     int             c;
  1252.        
  1253.     for (i = 0;i < strlen(string);i++)
  1254.     {
  1255.         c = toupper(string[i]) - HU_FONTSTART;
  1256.         if (c < 0 || c >= HU_FONTSIZE)
  1257.             w += 4;
  1258.         else
  1259.             w += SHORT (hu_font[c]->width);
  1260.     }
  1261.                
  1262.     return w;
  1263. }
  1264.  
  1265.  
  1266.  
  1267. //
  1268. //      Find string height from hu_font chars
  1269. //
  1270. int M_StringHeight(char* string)
  1271. {
  1272.     int             i;
  1273.     int             h;
  1274.     int             height = SHORT(hu_font[0]->height);
  1275.        
  1276.     h = height;
  1277.     for (i = 0;i < strlen(string);i++)
  1278.         if (string[i] == '\n')
  1279.             h += height;
  1280.                
  1281.     return h;
  1282. }
  1283.  
  1284.  
  1285. //
  1286. //      Write a string using the hu_font
  1287. //
  1288. void
  1289. M_WriteText
  1290. ( int           x,
  1291.   int           y,
  1292.   char*         string)
  1293. {
  1294.     int         w;
  1295.     char*       ch;
  1296.     int         c;
  1297.     int         cx;
  1298.     int         cy;
  1299.                
  1300.  
  1301.     ch = string;
  1302.     cx = x;
  1303.     cy = y;
  1304.        
  1305.     while(1)
  1306.     {
  1307.         c = *ch++;
  1308.         if (!c)
  1309.             break;
  1310.         if (c == '\n')
  1311.         {
  1312.             cx = x;
  1313.             cy += 12;
  1314.             continue;
  1315.         }
  1316.                
  1317.         c = toupper(c) - HU_FONTSTART;
  1318.         if (c < 0 || c>= HU_FONTSIZE)
  1319.         {
  1320.             cx += 4;
  1321.             continue;
  1322.         }
  1323.                
  1324.         w = SHORT (hu_font[c]->width);
  1325.         if (cx+w > SCREENWIDTH)
  1326.             break;
  1327.         V_DrawPatchDirect(cx, cy, 0, hu_font[c]);
  1328.         cx+=w;
  1329.     }
  1330. }
  1331.  
  1332.  
  1333.  
  1334. //
  1335. // CONTROL PANEL
  1336. //
  1337.  
  1338. //
  1339. // M_Responder
  1340. //
  1341. boolean M_Responder (event_t* ev)
  1342. {
  1343.     int             ch;
  1344.     int             i;
  1345.     static  int     joywait = 0;
  1346.     static  int     mousewait = 0;
  1347.     static  int     mousey = 0;
  1348.     static  int     lasty = 0;
  1349.     static  int     mousex = 0;
  1350.     static  int     lastx = 0;
  1351.        
  1352.     ch = -1;
  1353.        
  1354.     if (ev->type == ev_joystick && joywait < I_GetTime())
  1355.     {
  1356.         if (ev->data3 == -1)
  1357.         {
  1358.             ch = KEY_UPARROW;
  1359.             joywait = I_GetTime() + 5;
  1360.         }
  1361.         else if (ev->data3 == 1)
  1362.         {
  1363.             ch = KEY_DOWNARROW;
  1364.             joywait = I_GetTime() + 5;
  1365.         }
  1366.                
  1367.         if (ev->data2 == -1)
  1368.         {
  1369.             ch = KEY_LEFTARROW;
  1370.             joywait = I_GetTime() + 2;
  1371.         }
  1372.         else if (ev->data2 == 1)
  1373.         {
  1374.             ch = KEY_RIGHTARROW;
  1375.             joywait = I_GetTime() + 2;
  1376.         }
  1377.                
  1378.         if (ev->data1&1)
  1379.         {
  1380.             ch = KEY_ENTER;
  1381.             joywait = I_GetTime() + 5;
  1382.         }
  1383.         if (ev->data1&2)
  1384.         {
  1385.             ch = KEY_BACKSPACE;
  1386.             joywait = I_GetTime() + 5;
  1387.         }
  1388.     }
  1389.     else
  1390.     {
  1391.         if (ev->type == ev_mouse && mousewait < I_GetTime())
  1392.         {
  1393.             mousey += ev->data3;
  1394.             if (mousey < lasty-30)
  1395.             {
  1396.                 ch = KEY_DOWNARROW;
  1397.                 mousewait = I_GetTime() + 5;
  1398.                 mousey = lasty -= 30;
  1399.             }
  1400.             else if (mousey > lasty+30)
  1401.             {
  1402.                 ch = KEY_UPARROW;
  1403.                 mousewait = I_GetTime() + 5;
  1404.                 mousey = lasty += 30;
  1405.             }
  1406.                
  1407.             mousex += ev->data2;
  1408.             if (mousex < lastx-30)
  1409.             {
  1410.                 ch = KEY_LEFTARROW;
  1411.                 mousewait = I_GetTime() + 5;
  1412.                 mousex = lastx -= 30;
  1413.             }
  1414.             else if (mousex > lastx+30)
  1415.             {
  1416.                 ch = KEY_RIGHTARROW;
  1417.                 mousewait = I_GetTime() + 5;
  1418.                 mousex = lastx += 30;
  1419.             }
  1420.                
  1421.             if (ev->data1&1)
  1422.             {
  1423.                 ch = KEY_ENTER;
  1424.                 mousewait = I_GetTime() + 15;
  1425.             }
  1426.                        
  1427.             if (ev->data1&2)
  1428.             {
  1429.                 ch = KEY_BACKSPACE;
  1430.                 mousewait = I_GetTime() + 15;
  1431.             }
  1432.         }
  1433.         else
  1434.             if (ev->type == ev_keydown)
  1435.             {
  1436.                 ch = ev->data1;
  1437.             }
  1438.     }
  1439.    
  1440.     if (ch == -1)
  1441.         return false;
  1442.  
  1443.    
  1444.     // Save Game string input
  1445.     if (saveStringEnter)
  1446.     {
  1447.         switch(ch)
  1448.         {
  1449.           case KEY_BACKSPACE:
  1450.             if (saveCharIndex > 0)
  1451.             {
  1452.                 saveCharIndex--;
  1453.                 savegamestrings[saveSlot][saveCharIndex] = 0;
  1454.             }
  1455.             break;
  1456.                                
  1457.           case KEY_ESCAPE:
  1458.             saveStringEnter = 0;
  1459.             strcpy(&savegamestrings[saveSlot][0],saveOldString);
  1460.             break;
  1461.                                
  1462.           case KEY_ENTER:
  1463.             saveStringEnter = 0;
  1464.             if (savegamestrings[saveSlot][0])
  1465.                 M_DoSave(saveSlot);
  1466.             break;
  1467.                                
  1468.           default:
  1469.             ch = toupper(ch);
  1470.             if (ch != 32)
  1471.                 if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
  1472.                     break;
  1473.             if (ch >= 32 && ch <= 127 &&
  1474.                 saveCharIndex < SAVESTRINGSIZE-1 &&
  1475.                 M_StringWidth(savegamestrings[saveSlot]) <
  1476.                 (SAVESTRINGSIZE-2)*8)
  1477.             {
  1478.                 savegamestrings[saveSlot][saveCharIndex++] = ch;
  1479.                 savegamestrings[saveSlot][saveCharIndex] = 0;
  1480.             }
  1481.             break;
  1482.         }
  1483.         return true;
  1484.     }
  1485.    
  1486.     // Take care of any messages that need input
  1487.     if (messageToPrint)
  1488.     {
  1489.         if (messageNeedsInput == true &&
  1490.             !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE))
  1491.             return false;
  1492.                
  1493.         menuactive = messageLastMenuActive;
  1494.         messageToPrint = 0;
  1495.         if (messageRoutine)
  1496.             messageRoutine(ch);
  1497.                        
  1498.         menuactive = false;
  1499.         S_StartSound(NULL,sfx_swtchx);
  1500.         return true;
  1501.     }
  1502.        
  1503.     if (devparm && ch == KEY_F1)
  1504.     {
  1505.         G_ScreenShot ();
  1506.         return true;
  1507.     }
  1508.                
  1509.    
  1510.     // F-Keys
  1511.     if (!menuactive)
  1512.         switch(ch)
  1513.         {
  1514.           case KEY_MINUS:         // Screen size down
  1515.             if (automapactive || chat_on)
  1516.                 return false;
  1517.             M_SizeDisplay(0);
  1518.             S_StartSound(NULL,sfx_stnmov);
  1519.             return true;
  1520.                                
  1521.           case KEY_EQUALS:        // Screen size up
  1522.             if (automapactive || chat_on)
  1523.                 return false;
  1524.             M_SizeDisplay(1);
  1525.             S_StartSound(NULL,sfx_stnmov);
  1526.             return true;
  1527.                                
  1528.           case KEY_F1:            // Help key
  1529.             M_StartControlPanel ();
  1530.  
  1531.             if ( gamemode == retail )
  1532.               currentMenu = &ReadDef2;
  1533.             else
  1534.               currentMenu = &ReadDef1;
  1535.            
  1536.             itemOn = 0;
  1537.             S_StartSound(NULL,sfx_swtchn);
  1538.             return true;
  1539.                                
  1540.           case KEY_F2:            // Save
  1541.             M_StartControlPanel();
  1542.             S_StartSound(NULL,sfx_swtchn);
  1543.             M_SaveGame(0);
  1544.             return true;
  1545.                                
  1546.           case KEY_F3:            // Load
  1547.             M_StartControlPanel();
  1548.             S_StartSound(NULL,sfx_swtchn);
  1549.             M_LoadGame(0);
  1550.             return true;
  1551.                                
  1552.           case KEY_F4:            // Sound Volume
  1553.             M_StartControlPanel ();
  1554.             currentMenu = &SoundDef;
  1555.             itemOn = sfx_vol;
  1556.             S_StartSound(NULL,sfx_swtchn);
  1557.             return true;
  1558.                                
  1559.           case KEY_F5:            // Detail toggle
  1560.             M_ChangeDetail(0);
  1561.             S_StartSound(NULL,sfx_swtchn);
  1562.             return true;
  1563.                                
  1564.           case KEY_F6:            // Quicksave
  1565.             S_StartSound(NULL,sfx_swtchn);
  1566.             M_QuickSave();
  1567.             return true;
  1568.                                
  1569.           case KEY_F7:            // End game
  1570.             S_StartSound(NULL,sfx_swtchn);
  1571.             M_EndGame(0);
  1572.             return true;
  1573.                                
  1574.           case KEY_F8:            // Toggle messages
  1575.             M_ChangeMessages(0);
  1576.             S_StartSound(NULL,sfx_swtchn);
  1577.             return true;
  1578.                                
  1579.           case KEY_F9:            // Quickload
  1580.             S_StartSound(NULL,sfx_swtchn);
  1581.             M_QuickLoad();
  1582.             return true;
  1583.                                
  1584.           case KEY_F10:           // Quit DOOM
  1585.             S_StartSound(NULL,sfx_swtchn);
  1586.             M_QuitDOOM(0);
  1587.             return true;
  1588.                                
  1589.           case KEY_F11:           // gamma toggle
  1590.             usegamma++;
  1591.             if (usegamma > 4)
  1592.                 usegamma = 0;
  1593.             players[consoleplayer].message = gammamsg[usegamma];
  1594.             I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
  1595.             return true;
  1596.                                
  1597.         }
  1598.  
  1599.    
  1600.     // Pop-up menu?
  1601.     if (!menuactive)
  1602.     {
  1603.         if (ch == KEY_ESCAPE)
  1604.         {
  1605.             M_StartControlPanel ();
  1606.             S_StartSound(NULL,sfx_swtchn);
  1607.             return true;
  1608.         }
  1609.         return false;
  1610.     }
  1611.  
  1612.    
  1613.     // Keys usable within menu
  1614.     switch (ch)
  1615.     {
  1616.       case KEY_DOWNARROW:
  1617.         do
  1618.         {
  1619.             if (itemOn+1 > currentMenu->numitems-1)
  1620.                 itemOn = 0;
  1621.             else itemOn++;
  1622.             S_StartSound(NULL,sfx_pstop);
  1623.         } while(currentMenu->menuitems[itemOn].status==-1);
  1624.         return true;
  1625.                
  1626.       case KEY_UPARROW:
  1627.         do
  1628.         {
  1629.             if (!itemOn)
  1630.                 itemOn = currentMenu->numitems-1;
  1631.             else itemOn--;
  1632.             S_StartSound(NULL,sfx_pstop);
  1633.         } while(currentMenu->menuitems[itemOn].status==-1);
  1634.         return true;
  1635.  
  1636.       case KEY_LEFTARROW:
  1637.         if (currentMenu->menuitems[itemOn].routine &&
  1638.             currentMenu->menuitems[itemOn].status == 2)
  1639.         {
  1640.             S_StartSound(NULL,sfx_stnmov);
  1641.             currentMenu->menuitems[itemOn].routine(0);
  1642.         }
  1643.         return true;
  1644.                
  1645.       case KEY_RIGHTARROW:
  1646.         if (currentMenu->menuitems[itemOn].routine &&
  1647.             currentMenu->menuitems[itemOn].status == 2)
  1648.         {
  1649.             S_StartSound(NULL,sfx_stnmov);
  1650.             currentMenu->menuitems[itemOn].routine(1);
  1651.         }
  1652.         return true;
  1653.  
  1654.       case KEY_ENTER:
  1655.         if (currentMenu->menuitems[itemOn].routine &&
  1656.             currentMenu->menuitems[itemOn].status)
  1657.         {
  1658.             currentMenu->lastOn = itemOn;
  1659.             if (currentMenu->menuitems[itemOn].status == 2)
  1660.             {
  1661.                 currentMenu->menuitems[itemOn].routine(1);      // right arrow
  1662.                 S_StartSound(NULL,sfx_stnmov);
  1663.             }
  1664.             else
  1665.             {
  1666.                 currentMenu->menuitems[itemOn].routine(itemOn);
  1667.                 S_StartSound(NULL,sfx_pistol);
  1668.             }
  1669.         }
  1670.         return true;
  1671.                
  1672.       case KEY_ESCAPE:
  1673.         currentMenu->lastOn = itemOn;
  1674.         M_ClearMenus ();
  1675.         S_StartSound(NULL,sfx_swtchx);
  1676.         return true;
  1677.                
  1678.       case KEY_BACKSPACE:
  1679.         currentMenu->lastOn = itemOn;
  1680.         if (currentMenu->prevMenu)
  1681.         {
  1682.             currentMenu = currentMenu->prevMenu;
  1683.             itemOn = currentMenu->lastOn;
  1684.             S_StartSound(NULL,sfx_swtchn);
  1685.         }
  1686.         return true;
  1687.        
  1688.       default:
  1689.         for (i = itemOn+1;i < currentMenu->numitems;i++)
  1690.             if (currentMenu->menuitems[i].alphaKey == ch)
  1691.             {
  1692.                 itemOn = i;
  1693.                 S_StartSound(NULL,sfx_pstop);
  1694.                 return true;
  1695.             }
  1696.         for (i = 0;i <= itemOn;i++)
  1697.             if (currentMenu->menuitems[i].alphaKey == ch)
  1698.             {
  1699.                 itemOn = i;
  1700.                 S_StartSound(NULL,sfx_pstop);
  1701.                 return true;
  1702.             }
  1703.         break;
  1704.        
  1705.     }
  1706.  
  1707.     return false;
  1708. }
  1709.  
  1710.  
  1711.  
  1712. //
  1713. // M_StartControlPanel
  1714. //
  1715. void M_StartControlPanel (void)
  1716. {
  1717.     // intro might call this repeatedly
  1718.     if (menuactive)
  1719.         return;
  1720.    
  1721.     menuactive = 1;
  1722.     currentMenu = &MainDef;         // JDC
  1723.     itemOn = currentMenu->lastOn;   // JDC
  1724. }
  1725.  
  1726.  
  1727. //
  1728. // M_Drawer
  1729. // Called after the view has been rendered,
  1730. // but before it has been blitted.
  1731. //
  1732. void M_Drawer (void)
  1733. {
  1734.     static short        x;
  1735.     static short        y;
  1736.     short               i;
  1737.     short               max;
  1738.     char *p;
  1739.     int len;
  1740.     char                string[40];
  1741.     int                 start;
  1742.  
  1743.     inhelpscreens = false;
  1744.  
  1745.     // Horiz. & Vertically center string and print it.
  1746.     if (messageToPrint)
  1747.     {
  1748.           y = 100 - M_StringHeight(messageString)/2;
  1749.           p = messageString;
  1750.           len = strlen(p);
  1751.           while(*p)
  1752.           {
  1753.         for (i = 0;len;i++,len--)
  1754.         {
  1755.               if (*(p+i) == '\n')
  1756.                   { memset(string,0,40);
  1757.                     strncpy(string,p,i);
  1758.                     p+= i+1;
  1759.                     len-= 1;
  1760.                     break;
  1761.                   };
  1762.             };    
  1763.        
  1764.         if (len == 0)
  1765.         { strncpy(string,p,i);
  1766.           p+=i;
  1767.         };  
  1768.         x = 160 - M_StringWidth(string)/2;
  1769.         M_WriteText(x,y,string);
  1770.         y += SHORT(hu_font[0]->height);
  1771.           };
  1772.           return;
  1773.     };
  1774.  
  1775.     if (!menuactive)
  1776.         return;
  1777.  
  1778.     if (currentMenu->routine)
  1779.         currentMenu->routine();         // call Draw routine
  1780.    
  1781.     // DRAW MENU
  1782.     x = currentMenu->x;
  1783.     y = currentMenu->y;
  1784.     max = currentMenu->numitems;
  1785.  
  1786.     for (i=0;i<max;i++)
  1787.     {
  1788.         if (currentMenu->menuitems[i].name[0])
  1789.             V_DrawPatchDirect (x,y,0,
  1790.                                W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE));
  1791.         y += LINEHEIGHT;
  1792.     }
  1793.  
  1794.    
  1795.     // DRAW SKULL
  1796.     V_DrawPatchDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
  1797.                       W_CacheLumpName(skullName[whichSkull],PU_CACHE));
  1798.  
  1799. }
  1800.  
  1801.  
  1802. //
  1803. // M_ClearMenus
  1804. //
  1805. void M_ClearMenus (void)
  1806. {
  1807.     menuactive = 0;
  1808.     // if (!netgame && usergame && paused)
  1809.     //       sendpause = true;
  1810. }
  1811.  
  1812.  
  1813.  
  1814.  
  1815. //
  1816. // M_SetupNextMenu
  1817. //
  1818. void M_SetupNextMenu(menu_t *menudef)
  1819. {
  1820.     currentMenu = menudef;
  1821.     itemOn = currentMenu->lastOn;
  1822. }
  1823.  
  1824.  
  1825. //
  1826. // M_Ticker
  1827. //
  1828. void M_Ticker (void)
  1829. {
  1830.     if (--skullAnimCounter <= 0)
  1831.     {
  1832.         whichSkull ^= 1;
  1833.         skullAnimCounter = 8;
  1834.     }
  1835. }
  1836.  
  1837.  
  1838. //
  1839. // M_Init
  1840. //
  1841. void M_Init (void)
  1842. {
  1843.     currentMenu = &MainDef;
  1844.     menuactive = 0;
  1845.     itemOn = currentMenu->lastOn;
  1846.     whichSkull = 0;
  1847.     skullAnimCounter = 10;
  1848.     screenSize = screenblocks - 3;
  1849.     messageToPrint = 0;
  1850.     messageString = NULL;
  1851.     messageLastMenuActive = menuactive;
  1852.     quickSaveSlot = -1;
  1853.  
  1854.     // Here we could catch other version dependencies,
  1855.     //  like HELP1/2, and four episodes.
  1856.  
  1857.  
  1858.     switch ( gamemode )
  1859.     {
  1860.       case commercial:
  1861.         // This is used because DOOM 2 had only one HELP
  1862.         //  page. I use CREDIT as second page now, but
  1863.         //  kept this hack for educational purposes.
  1864.         MainMenu[readthis] = MainMenu[quitdoom];
  1865.         MainDef.numitems--;
  1866.         MainDef.y += 8;
  1867.         NewDef.prevMenu = &MainDef;
  1868.         ReadDef1.routine = M_DrawReadThis1;
  1869.         ReadDef1.x = 330;
  1870.         ReadDef1.y = 165;
  1871.         ReadMenu1[0].routine = M_FinishReadThis;
  1872.         break;
  1873.       case shareware:
  1874.         // Episode 2 and 3 are handled,
  1875.         //  branching to an ad screen.
  1876.       case registered:
  1877.         // We need to remove the fourth episode.
  1878.         EpiDef.numitems--;
  1879.         break;
  1880.       case retail:
  1881.         // We are fine.
  1882.       default:
  1883.         break;
  1884.     }
  1885.    
  1886. }
  1887.  
  1888.