Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "quakedef.h"
  21.  
  22. #ifdef _WIN32
  23. #include "winquake.h"
  24. #endif
  25.  
  26. void (*vid_menudrawfn)(void);
  27. void (*vid_menukeyfn)(int key);
  28.  
  29. enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
  30.  
  31. void M_Menu_Main_f (void);
  32.         void M_Menu_SinglePlayer_f (void);
  33.                 void M_Menu_Load_f (void);
  34.                 void M_Menu_Save_f (void);
  35.         void M_Menu_MultiPlayer_f (void);
  36.                 void M_Menu_Setup_f (void);
  37.                 void M_Menu_Net_f (void);
  38.         void M_Menu_Options_f (void);
  39.                 void M_Menu_Keys_f (void);
  40.                 void M_Menu_Video_f (void);
  41.         void M_Menu_Help_f (void);
  42.         void M_Menu_Quit_f (void);
  43. void M_Menu_SerialConfig_f (void);
  44.         void M_Menu_ModemConfig_f (void);
  45. void M_Menu_LanConfig_f (void);
  46. void M_Menu_GameOptions_f (void);
  47. void M_Menu_Search_f (void);
  48. void M_Menu_ServerList_f (void);
  49.  
  50. void M_Main_Draw (void);
  51.         void M_SinglePlayer_Draw (void);
  52.                 void M_Load_Draw (void);
  53.                 void M_Save_Draw (void);
  54.         void M_MultiPlayer_Draw (void);
  55.                 void M_Setup_Draw (void);
  56.                 void M_Net_Draw (void);
  57.         void M_Options_Draw (void);
  58.                 void M_Keys_Draw (void);
  59.                 void M_Video_Draw (void);
  60.         void M_Help_Draw (void);
  61.         void M_Quit_Draw (void);
  62. void M_SerialConfig_Draw (void);
  63.         void M_ModemConfig_Draw (void);
  64. void M_LanConfig_Draw (void);
  65. void M_GameOptions_Draw (void);
  66. void M_Search_Draw (void);
  67. void M_ServerList_Draw (void);
  68.  
  69. void M_Main_Key (int key);
  70.         void M_SinglePlayer_Key (int key);
  71.                 void M_Load_Key (int key);
  72.                 void M_Save_Key (int key);
  73.         void M_MultiPlayer_Key (int key);
  74.                 void M_Setup_Key (int key);
  75.                 void M_Net_Key (int key);
  76.         void M_Options_Key (int key);
  77.                 void M_Keys_Key (int key);
  78.                 void M_Video_Key (int key);
  79.         void M_Help_Key (int key);
  80.         void M_Quit_Key (int key);
  81. void M_SerialConfig_Key (int key);
  82.         void M_ModemConfig_Key (int key);
  83. void M_LanConfig_Key (int key);
  84. void M_GameOptions_Key (int key);
  85. void M_Search_Key (int key);
  86. void M_ServerList_Key (int key);
  87.  
  88. qboolean        m_entersound;           // play after drawing a frame, so caching
  89.                                                                 // won't disrupt the sound
  90. qboolean        m_recursiveDraw;
  91.  
  92. int                     m_return_state;
  93. qboolean        m_return_onerror;
  94. char            m_return_reason [32];
  95.  
  96. #define StartingGame    (m_multiplayer_cursor == 1)
  97. #define JoiningGame             (m_multiplayer_cursor == 0)
  98. #define SerialConfig    (m_net_cursor == 0)
  99. #define DirectConfig    (m_net_cursor == 1)
  100. #define IPXConfig               (m_net_cursor == 2)
  101. #define TCPIPConfig             (m_net_cursor == 3)
  102.  
  103. void M_ConfigureNetSubsystem(void);
  104.  
  105. /*
  106. ================
  107. M_DrawCharacter
  108.  
  109. Draws one solid graphics character
  110. ================
  111. */
  112. void M_DrawCharacter (int cx, int line, int num)
  113. {
  114.         Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
  115. }
  116.  
  117. void M_Print (int cx, int cy, char *str)
  118. {
  119.         while (*str)
  120.         {
  121.                 M_DrawCharacter (cx, cy, (*str)+128);
  122.                 str++;
  123.                 cx += 8;
  124.         }
  125. }
  126.  
  127. void M_PrintWhite (int cx, int cy, char *str)
  128. {
  129.         while (*str)
  130.         {
  131.                 M_DrawCharacter (cx, cy, *str);
  132.                 str++;
  133.                 cx += 8;
  134.         }
  135. }
  136.  
  137. void M_DrawTransPic (int x, int y, qpic_t *pic)
  138. {
  139.         Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
  140. }
  141.  
  142. void M_DrawPic (int x, int y, qpic_t *pic)
  143. {
  144.         Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
  145. }
  146.  
  147. byte identityTable[256];
  148. byte translationTable[256];
  149.  
  150. void M_BuildTranslationTable(int top, int bottom)
  151. {
  152.         int             j;
  153.         byte    *dest, *source;
  154.  
  155.         for (j = 0; j < 256; j++)
  156.                 identityTable[j] = j;
  157.         dest = translationTable;
  158.         source = identityTable;
  159.         memcpy (dest, source, 256);
  160.  
  161.         if (top < 128)  // the artists made some backwards ranges.  sigh.
  162.                 memcpy (dest + TOP_RANGE, source + top, 16);
  163.         else
  164.                 for (j=0 ; j<16 ; j++)
  165.                         dest[TOP_RANGE+j] = source[top+15-j];
  166.  
  167.         if (bottom < 128)
  168.                 memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
  169.         else
  170.                 for (j=0 ; j<16 ; j++)
  171.                         dest[BOTTOM_RANGE+j] = source[bottom+15-j];
  172. }
  173.  
  174.  
  175. void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
  176. {
  177.         Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
  178. }
  179.  
  180.  
  181. void M_DrawTextBox (int x, int y, int width, int lines)
  182. {
  183.         qpic_t  *p;
  184.         int             cx, cy;
  185.         int             n;
  186.  
  187.         // draw left side
  188.         cx = x;
  189.         cy = y;
  190.         p = Draw_CachePic ("gfx/box_tl.lmp");
  191.         M_DrawTransPic (cx, cy, p);
  192.         p = Draw_CachePic ("gfx/box_ml.lmp");
  193.         for (n = 0; n < lines; n++)
  194.         {
  195.                 cy += 8;
  196.                 M_DrawTransPic (cx, cy, p);
  197.         }
  198.         p = Draw_CachePic ("gfx/box_bl.lmp");
  199.         M_DrawTransPic (cx, cy+8, p);
  200.  
  201.         // draw middle
  202.         cx += 8;
  203.         while (width > 0)
  204.         {
  205.                 cy = y;
  206.                 p = Draw_CachePic ("gfx/box_tm.lmp");
  207.                 M_DrawTransPic (cx, cy, p);
  208.                 p = Draw_CachePic ("gfx/box_mm.lmp");
  209.                 for (n = 0; n < lines; n++)
  210.                 {
  211.                         cy += 8;
  212.                         if (n == 1)
  213.                                 p = Draw_CachePic ("gfx/box_mm2.lmp");
  214.                         M_DrawTransPic (cx, cy, p);
  215.                 }
  216.                 p = Draw_CachePic ("gfx/box_bm.lmp");
  217.                 M_DrawTransPic (cx, cy+8, p);
  218.                 width -= 2;
  219.                 cx += 16;
  220.         }
  221.  
  222.         // draw right side
  223.         cy = y;
  224.         p = Draw_CachePic ("gfx/box_tr.lmp");
  225.         M_DrawTransPic (cx, cy, p);
  226.         p = Draw_CachePic ("gfx/box_mr.lmp");
  227.         for (n = 0; n < lines; n++)
  228.         {
  229.                 cy += 8;
  230.                 M_DrawTransPic (cx, cy, p);
  231.         }
  232.         p = Draw_CachePic ("gfx/box_br.lmp");
  233.         M_DrawTransPic (cx, cy+8, p);
  234. }
  235.  
  236. //=============================================================================
  237.  
  238. int m_save_demonum;
  239.  
  240. /*
  241. ================
  242. M_ToggleMenu_f
  243. ================
  244. */
  245. void M_ToggleMenu_f (void)
  246. {
  247.         m_entersound = true;
  248.  
  249.         if (key_dest == key_menu)
  250.         {
  251.                 if (m_state != m_main)
  252.                 {
  253.                         M_Menu_Main_f ();
  254.                         return;
  255.                 }
  256.                 key_dest = key_game;
  257.                 m_state = m_none;
  258.                 return;
  259.         }
  260.         if (key_dest == key_console)
  261.         {
  262.                 Con_ToggleConsole_f ();
  263.         }
  264.         else
  265.         {
  266.                 M_Menu_Main_f ();
  267.         }
  268. }
  269.  
  270.  
  271. //=============================================================================
  272. /* MAIN MENU */
  273.  
  274. int     m_main_cursor;
  275. #define MAIN_ITEMS      5
  276.  
  277.  
  278. void M_Menu_Main_f (void)
  279. {
  280.         if (key_dest != key_menu)
  281.         {
  282.                 m_save_demonum = cls.demonum;
  283.                 cls.demonum = -1;
  284.         }
  285.         key_dest = key_menu;
  286.         m_state = m_main;
  287.         m_entersound = true;
  288. }
  289.  
  290.  
  291. void M_Main_Draw (void)
  292. {
  293.         int             f;
  294.         qpic_t  *p;
  295.  
  296.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  297.         p = Draw_CachePic ("gfx/ttl_main.lmp");
  298.         M_DrawPic ( (320-p->width)/2, 4, p);
  299.         M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
  300.  
  301.         f = (int)(host_time * 10)%6;
  302.  
  303.         M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  304. }
  305.  
  306.  
  307. void M_Main_Key (int key)
  308. {
  309.         switch (key)
  310.         {
  311.         case K_ESCAPE:
  312.                 key_dest = key_game;
  313.                 m_state = m_none;
  314.                 cls.demonum = m_save_demonum;
  315.                 if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
  316.                         CL_NextDemo ();
  317.                 break;
  318.  
  319.         case K_DOWNARROW:
  320.                 S_LocalSound ("misc/menu1.wav");
  321.                 if (++m_main_cursor >= MAIN_ITEMS)
  322.                         m_main_cursor = 0;
  323.                 break;
  324.  
  325.         case K_UPARROW:
  326.                 S_LocalSound ("misc/menu1.wav");
  327.                 if (--m_main_cursor < 0)
  328.                         m_main_cursor = MAIN_ITEMS - 1;
  329.                 break;
  330.  
  331.         case K_ENTER:
  332.                 m_entersound = true;
  333.  
  334.                 switch (m_main_cursor)
  335.                 {
  336.                 case 0:
  337.                         M_Menu_SinglePlayer_f ();
  338.                         break;
  339.  
  340.                 case 1:
  341.                         M_Menu_MultiPlayer_f ();
  342.                         break;
  343.  
  344.                 case 2:
  345.                         M_Menu_Options_f ();
  346.                         break;
  347.  
  348.                 case 3:
  349.                         M_Menu_Help_f ();
  350.                         break;
  351.  
  352.                 case 4:
  353.                         M_Menu_Quit_f ();
  354.                         break;
  355.                 }
  356.         }
  357. }
  358.  
  359. //=============================================================================
  360. /* SINGLE PLAYER MENU */
  361.  
  362. int     m_singleplayer_cursor;
  363. #define SINGLEPLAYER_ITEMS      3
  364.  
  365.  
  366. void M_Menu_SinglePlayer_f (void)
  367. {
  368.         key_dest = key_menu;
  369.         m_state = m_singleplayer;
  370.         m_entersound = true;
  371. }
  372.  
  373.  
  374. void M_SinglePlayer_Draw (void)
  375. {
  376.         int             f;
  377.         qpic_t  *p;
  378.  
  379.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  380.         p = Draw_CachePic ("gfx/ttl_sgl.lmp");
  381.         M_DrawPic ( (320-p->width)/2, 4, p);
  382.         M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
  383.  
  384.         f = (int)(host_time * 10)%6;
  385.  
  386.         M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  387. }
  388.  
  389.  
  390. void M_SinglePlayer_Key (int key)
  391. {
  392.         switch (key)
  393.         {
  394.         case K_ESCAPE:
  395.                 M_Menu_Main_f ();
  396.                 break;
  397.  
  398.         case K_DOWNARROW:
  399.                 S_LocalSound ("misc/menu1.wav");
  400.                 if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
  401.                         m_singleplayer_cursor = 0;
  402.                 break;
  403.  
  404.         case K_UPARROW:
  405.                 S_LocalSound ("misc/menu1.wav");
  406.                 if (--m_singleplayer_cursor < 0)
  407.                         m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
  408.                 break;
  409.  
  410.         case K_ENTER:
  411.                 m_entersound = true;
  412.  
  413.                 switch (m_singleplayer_cursor)
  414.                 {
  415.                 case 0:
  416.                         if (sv.active)
  417.                                 if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n"))
  418.                                         break;
  419.                         key_dest = key_game;
  420.                         if (sv.active)
  421.                                 Cbuf_AddText ("disconnect\n");
  422.                         Cbuf_AddText ("maxplayers 1\n");
  423.                         Cbuf_AddText ("map start\n");
  424.                         break;
  425.  
  426.                 case 1:
  427.                         M_Menu_Load_f ();
  428.                         break;
  429.  
  430.                 case 2:
  431.                         M_Menu_Save_f ();
  432.                         break;
  433.                 }
  434.         }
  435. }
  436.  
  437. //=============================================================================
  438. /* LOAD/SAVE MENU */
  439.  
  440. int             load_cursor;            // 0 < load_cursor < MAX_SAVEGAMES
  441.  
  442. #define MAX_SAVEGAMES           12
  443. char    m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
  444. int             loadable[MAX_SAVEGAMES];
  445.  
  446. void M_ScanSaves (void)
  447. {
  448.         int             i, j;
  449.         char    name[MAX_OSPATH];
  450.         FILE    *f;
  451.         int             version;
  452.  
  453.         for (i=0 ; i<MAX_SAVEGAMES ; i++)
  454.         {
  455.                 strcpy (m_filenames[i], "--- UNUSED SLOT ---");
  456.                 loadable[i] = false;
  457.                 sprintf (name, "%s/s%i.sav", com_gamedir, i);
  458.                 f = fopen (name, "r");
  459.                 if (!f)
  460.                         continue;
  461.                 fscanf (f, "%i\n", &version);
  462.                 fscanf (f, "%79s\n", name);
  463.                 strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);
  464.  
  465.         // change _ back to space
  466.                 for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
  467.                         if (m_filenames[i][j] == '_')
  468.                                 m_filenames[i][j] = ' ';
  469.                 loadable[i] = true;
  470.                 fclose (f);
  471.         }
  472. }
  473.  
  474. void M_Menu_Load_f (void)
  475. {
  476.         m_entersound = true;
  477.         m_state = m_load;
  478.         key_dest = key_menu;
  479.         M_ScanSaves ();
  480. }
  481.  
  482.  
  483. void M_Menu_Save_f (void)
  484. {
  485.         if (!sv.active)
  486.                 return;
  487.         if (cl.intermission)
  488.                 return;
  489.         if (svs.maxclients != 1)
  490.                 return;
  491.         m_entersound = true;
  492.         m_state = m_save;
  493.         key_dest = key_menu;
  494.         M_ScanSaves ();
  495. }
  496.  
  497.  
  498. void M_Load_Draw (void)
  499. {
  500.         int             i;
  501.         qpic_t  *p;
  502.  
  503.         p = Draw_CachePic ("gfx/p_load.lmp");
  504.         M_DrawPic ( (320-p->width)/2, 4, p);
  505.  
  506.         for (i=0 ; i< MAX_SAVEGAMES; i++)
  507.                 M_Print (16, 32 + 8*i, m_filenames[i]);
  508.  
  509. // line cursor
  510.         M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
  511. }
  512.  
  513.  
  514. void M_Save_Draw (void)
  515. {
  516.         int             i;
  517.         qpic_t  *p;
  518.  
  519.         p = Draw_CachePic ("gfx/p_save.lmp");
  520.         M_DrawPic ( (320-p->width)/2, 4, p);
  521.  
  522.         for (i=0 ; i<MAX_SAVEGAMES ; i++)
  523.                 M_Print (16, 32 + 8*i, m_filenames[i]);
  524.  
  525. // line cursor
  526.         M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
  527. }
  528.  
  529.  
  530. void M_Load_Key (int k)
  531. {
  532.         switch (k)
  533.         {
  534.         case K_ESCAPE:
  535.                 M_Menu_SinglePlayer_f ();
  536.                 break;
  537.  
  538.         case K_ENTER:
  539.                 S_LocalSound ("misc/menu2.wav");
  540.                 if (!loadable[load_cursor])
  541.                         return;
  542.                 m_state = m_none;
  543.                 key_dest = key_game;
  544.  
  545.         // Host_Loadgame_f can't bring up the loading plaque because too much
  546.         // stack space has been used, so do it now
  547.                 SCR_BeginLoadingPlaque ();
  548.  
  549.         // issue the load command
  550.                 Cbuf_AddText (va ("load s%i\n", load_cursor) );
  551.                 return;
  552.  
  553.         case K_UPARROW:
  554.         case K_LEFTARROW:
  555.                 S_LocalSound ("misc/menu1.wav");
  556.                 load_cursor--;
  557.                 if (load_cursor < 0)
  558.                         load_cursor = MAX_SAVEGAMES-1;
  559.                 break;
  560.  
  561.         case K_DOWNARROW:
  562.         case K_RIGHTARROW:
  563.                 S_LocalSound ("misc/menu1.wav");
  564.                 load_cursor++;
  565.                 if (load_cursor >= MAX_SAVEGAMES)
  566.                         load_cursor = 0;
  567.                 break;
  568.         }
  569. }
  570.  
  571.  
  572. void M_Save_Key (int k)
  573. {
  574.         switch (k)
  575.         {
  576.         case K_ESCAPE:
  577.                 M_Menu_SinglePlayer_f ();
  578.                 break;
  579.  
  580.         case K_ENTER:
  581.                 m_state = m_none;
  582.                 key_dest = key_game;
  583.                 Cbuf_AddText (va("save s%i\n", load_cursor));
  584.                 return;
  585.  
  586.         case K_UPARROW:
  587.         case K_LEFTARROW:
  588.                 S_LocalSound ("misc/menu1.wav");
  589.                 load_cursor--;
  590.                 if (load_cursor < 0)
  591.                         load_cursor = MAX_SAVEGAMES-1;
  592.                 break;
  593.  
  594.         case K_DOWNARROW:
  595.         case K_RIGHTARROW:
  596.                 S_LocalSound ("misc/menu1.wav");
  597.                 load_cursor++;
  598.                 if (load_cursor >= MAX_SAVEGAMES)
  599.                         load_cursor = 0;
  600.                 break;
  601.         }
  602. }
  603.  
  604. //=============================================================================
  605. /* MULTIPLAYER MENU */
  606.  
  607. int     m_multiplayer_cursor;
  608. #define MULTIPLAYER_ITEMS       3
  609.  
  610.  
  611. void M_Menu_MultiPlayer_f (void)
  612. {
  613.         key_dest = key_menu;
  614.         m_state = m_multiplayer;
  615.         m_entersound = true;
  616. }
  617.  
  618.  
  619. void M_MultiPlayer_Draw (void)
  620. {
  621.         int             f;
  622.         qpic_t  *p;
  623.  
  624.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  625.         p = Draw_CachePic ("gfx/p_multi.lmp");
  626.         M_DrawPic ( (320-p->width)/2, 4, p);
  627.         M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
  628.  
  629.         f = (int)(host_time * 10)%6;
  630.  
  631.         M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  632.  
  633.         if (serialAvailable || ipxAvailable || tcpipAvailable)
  634.                 return;
  635.         M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
  636. }
  637.  
  638.  
  639. void M_MultiPlayer_Key (int key)
  640. {
  641.         switch (key)
  642.         {
  643.         case K_ESCAPE:
  644.                 M_Menu_Main_f ();
  645.                 break;
  646.  
  647.         case K_DOWNARROW:
  648.                 S_LocalSound ("misc/menu1.wav");
  649.                 if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
  650.                         m_multiplayer_cursor = 0;
  651.                 break;
  652.  
  653.         case K_UPARROW:
  654.                 S_LocalSound ("misc/menu1.wav");
  655.                 if (--m_multiplayer_cursor < 0)
  656.                         m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
  657.                 break;
  658.  
  659.         case K_ENTER:
  660.                 m_entersound = true;
  661.                 switch (m_multiplayer_cursor)
  662.                 {
  663.                 case 0:
  664.                         if (serialAvailable || ipxAvailable || tcpipAvailable)
  665.                                 M_Menu_Net_f ();
  666.                         break;
  667.  
  668.                 case 1:
  669.                         if (serialAvailable || ipxAvailable || tcpipAvailable)
  670.                                 M_Menu_Net_f ();
  671.                         break;
  672.  
  673.                 case 2:
  674.                         M_Menu_Setup_f ();
  675.                         break;
  676.                 }
  677.         }
  678. }
  679.  
  680. //=============================================================================
  681. /* SETUP MENU */
  682.  
  683. int             setup_cursor = 4;
  684. int             setup_cursor_table[] = {40, 56, 80, 104, 140};
  685.  
  686. char    setup_hostname[16];
  687. char    setup_myname[16];
  688. int             setup_oldtop;
  689. int             setup_oldbottom;
  690. int             setup_top;
  691. int             setup_bottom;
  692.  
  693. #define NUM_SETUP_CMDS  5
  694.  
  695. void M_Menu_Setup_f (void)
  696. {
  697.         key_dest = key_menu;
  698.         m_state = m_setup;
  699.         m_entersound = true;
  700.         Q_strcpy(setup_myname, cl_name.string);
  701.         Q_strcpy(setup_hostname, hostname.string);
  702.         setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
  703.         setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
  704. }
  705.  
  706.  
  707. void M_Setup_Draw (void)
  708. {
  709.         qpic_t  *p;
  710.  
  711.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  712.         p = Draw_CachePic ("gfx/p_multi.lmp");
  713.         M_DrawPic ( (320-p->width)/2, 4, p);
  714.  
  715.         M_Print (64, 40, "Hostname");
  716.         M_DrawTextBox (160, 32, 16, 1);
  717.         M_Print (168, 40, setup_hostname);
  718.  
  719.         M_Print (64, 56, "Your name");
  720.         M_DrawTextBox (160, 48, 16, 1);
  721.         M_Print (168, 56, setup_myname);
  722.  
  723.         M_Print (64, 80, "Shirt color");
  724.         M_Print (64, 104, "Pants color");
  725.  
  726.         M_DrawTextBox (64, 140-8, 14, 1);
  727.         M_Print (72, 140, "Accept Changes");
  728.  
  729.         p = Draw_CachePic ("gfx/bigbox.lmp");
  730.         M_DrawTransPic (160, 64, p);
  731.         p = Draw_CachePic ("gfx/menuplyr.lmp");
  732.         M_BuildTranslationTable(setup_top*16, setup_bottom*16);
  733.         M_DrawTransPicTranslate (172, 72, p);
  734.  
  735.         M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
  736.  
  737.         if (setup_cursor == 0)
  738.                 M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
  739.  
  740.         if (setup_cursor == 1)
  741.                 M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
  742. }
  743.  
  744.  
  745. void M_Setup_Key (int k)
  746. {
  747.         int                     l;
  748.  
  749.         switch (k)
  750.         {
  751.         case K_ESCAPE:
  752.                 M_Menu_MultiPlayer_f ();
  753.                 break;
  754.  
  755.         case K_UPARROW:
  756.                 S_LocalSound ("misc/menu1.wav");
  757.                 setup_cursor--;
  758.                 if (setup_cursor < 0)
  759.                         setup_cursor = NUM_SETUP_CMDS-1;
  760.                 break;
  761.  
  762.         case K_DOWNARROW:
  763.                 S_LocalSound ("misc/menu1.wav");
  764.                 setup_cursor++;
  765.                 if (setup_cursor >= NUM_SETUP_CMDS)
  766.                         setup_cursor = 0;
  767.                 break;
  768.  
  769.         case K_LEFTARROW:
  770.                 if (setup_cursor < 2)
  771.                         return;
  772.                 S_LocalSound ("misc/menu3.wav");
  773.                 if (setup_cursor == 2)
  774.                         setup_top = setup_top - 1;
  775.                 if (setup_cursor == 3)
  776.                         setup_bottom = setup_bottom - 1;
  777.                 break;
  778.         case K_RIGHTARROW:
  779.                 if (setup_cursor < 2)
  780.                         return;
  781. forward:
  782.                 S_LocalSound ("misc/menu3.wav");
  783.                 if (setup_cursor == 2)
  784.                         setup_top = setup_top + 1;
  785.                 if (setup_cursor == 3)
  786.                         setup_bottom = setup_bottom + 1;
  787.                 break;
  788.  
  789.         case K_ENTER:
  790.                 if (setup_cursor == 0 || setup_cursor == 1)
  791.                         return;
  792.  
  793.                 if (setup_cursor == 2 || setup_cursor == 3)
  794.                         goto forward;
  795.  
  796.                 // setup_cursor == 4 (OK)
  797.                 if (Q_strcmp(cl_name.string, setup_myname) != 0)
  798.                         Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
  799.                 if (Q_strcmp(hostname.string, setup_hostname) != 0)
  800.                         Cvar_Set("hostname", setup_hostname);
  801.                 if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
  802.                         Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
  803.                 m_entersound = true;
  804.                 M_Menu_MultiPlayer_f ();
  805.                 break;
  806.  
  807.         case K_BACKSPACE:
  808.                 if (setup_cursor == 0)
  809.                 {
  810.                         if (strlen(setup_hostname))
  811.                                 setup_hostname[strlen(setup_hostname)-1] = 0;
  812.                 }
  813.  
  814.                 if (setup_cursor == 1)
  815.                 {
  816.                         if (strlen(setup_myname))
  817.                                 setup_myname[strlen(setup_myname)-1] = 0;
  818.                 }
  819.                 break;
  820.  
  821.         default:
  822.                 if (k < 32 || k > 127)
  823.                         break;
  824.                 if (setup_cursor == 0)
  825.                 {
  826.                         l = strlen(setup_hostname);
  827.                         if (l < 15)
  828.                         {
  829.                                 setup_hostname[l+1] = 0;
  830.                                 setup_hostname[l] = k;
  831.                         }
  832.                 }
  833.                 if (setup_cursor == 1)
  834.                 {
  835.                         l = strlen(setup_myname);
  836.                         if (l < 15)
  837.                         {
  838.                                 setup_myname[l+1] = 0;
  839.                                 setup_myname[l] = k;
  840.                         }
  841.                 }
  842.         }
  843.  
  844.         if (setup_top > 13)
  845.                 setup_top = 0;
  846.         if (setup_top < 0)
  847.                 setup_top = 13;
  848.         if (setup_bottom > 13)
  849.                 setup_bottom = 0;
  850.         if (setup_bottom < 0)
  851.                 setup_bottom = 13;
  852. }
  853.  
  854. //=============================================================================
  855. /* NET MENU */
  856.  
  857. int     m_net_cursor;
  858. int m_net_items;
  859. int m_net_saveHeight;
  860.  
  861. char *net_helpMessage [] =
  862. {
  863. /* .........1.........2.... */
  864.   "                        ",
  865.   " Two computers connected",
  866.   "   through two modems.  ",
  867.   "                        ",
  868.  
  869.   "                        ",
  870.   " Two computers connected",
  871.   " by a null-modem cable. ",
  872.   "                        ",
  873.  
  874.   " Novell network LANs    ",
  875.   " or Windows 95 DOS-box. ",
  876.   "                        ",
  877.   "(LAN=Local Area Network)",
  878.  
  879.   " Commonly used to play  ",
  880.   " over the Internet, but ",
  881.   " also used on a Local   ",
  882.   " Area Network.          "
  883. };
  884.  
  885. void M_Menu_Net_f (void)
  886. {
  887.         key_dest = key_menu;
  888.         m_state = m_net;
  889.         m_entersound = true;
  890.         m_net_items = 4;
  891.  
  892.         if (m_net_cursor >= m_net_items)
  893.                 m_net_cursor = 0;
  894.         m_net_cursor--;
  895.         M_Net_Key (K_DOWNARROW);
  896. }
  897.  
  898.  
  899. void M_Net_Draw (void)
  900. {
  901.         int             f;
  902.         qpic_t  *p;
  903.  
  904.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  905.         p = Draw_CachePic ("gfx/p_multi.lmp");
  906.         M_DrawPic ( (320-p->width)/2, 4, p);
  907.  
  908.         f = 32;
  909.  
  910.         if (serialAvailable)
  911.         {
  912.                 p = Draw_CachePic ("gfx/netmen1.lmp");
  913.         }
  914.         else
  915.         {
  916. #ifdef _WIN32
  917.                 p = NULL;
  918. #else
  919.                 p = Draw_CachePic ("gfx/dim_modm.lmp");
  920. #endif
  921.         }
  922.  
  923.         if (p)
  924.                 M_DrawTransPic (72, f, p);
  925.  
  926.         f += 19;
  927.  
  928.         if (serialAvailable)
  929.         {
  930.                 p = Draw_CachePic ("gfx/netmen2.lmp");
  931.         }
  932.         else
  933.         {
  934. #ifdef _WIN32
  935.                 p = NULL;
  936. #else
  937.                 p = Draw_CachePic ("gfx/dim_drct.lmp");
  938. #endif
  939.         }
  940.  
  941.         if (p)
  942.                 M_DrawTransPic (72, f, p);
  943.  
  944.         f += 19;
  945.         if (ipxAvailable)
  946.                 p = Draw_CachePic ("gfx/netmen3.lmp");
  947.         else
  948.                 p = Draw_CachePic ("gfx/dim_ipx.lmp");
  949.         M_DrawTransPic (72, f, p);
  950.  
  951.         f += 19;
  952.         if (tcpipAvailable)
  953.                 p = Draw_CachePic ("gfx/netmen4.lmp");
  954.         else
  955.                 p = Draw_CachePic ("gfx/dim_tcp.lmp");
  956.         M_DrawTransPic (72, f, p);
  957.  
  958.         if (m_net_items == 5)   // JDC, could just be removed
  959.         {
  960.                 f += 19;
  961.                 p = Draw_CachePic ("gfx/netmen5.lmp");
  962.                 M_DrawTransPic (72, f, p);
  963.         }
  964.  
  965.         f = (320-26*8)/2;
  966.         M_DrawTextBox (f, 134, 24, 4);
  967.         f += 8;
  968.         M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
  969.         M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
  970.         M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
  971.         M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
  972.  
  973.         f = (int)(host_time * 10)%6;
  974.         M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  975. }
  976.  
  977.  
  978. void M_Net_Key (int k)
  979. {
  980. again:
  981.         switch (k)
  982.         {
  983.         case K_ESCAPE:
  984.                 M_Menu_MultiPlayer_f ();
  985.                 break;
  986.  
  987.         case K_DOWNARROW:
  988.                 S_LocalSound ("misc/menu1.wav");
  989.                 if (++m_net_cursor >= m_net_items)
  990.                         m_net_cursor = 0;
  991.                 break;
  992.  
  993.         case K_UPARROW:
  994.                 S_LocalSound ("misc/menu1.wav");
  995.                 if (--m_net_cursor < 0)
  996.                         m_net_cursor = m_net_items - 1;
  997.                 break;
  998.  
  999.         case K_ENTER:
  1000.                 m_entersound = true;
  1001.  
  1002.                 switch (m_net_cursor)
  1003.                 {
  1004.                 case 0:
  1005.                         M_Menu_SerialConfig_f ();
  1006.                         break;
  1007.  
  1008.                 case 1:
  1009.                         M_Menu_SerialConfig_f ();
  1010.                         break;
  1011.  
  1012.                 case 2:
  1013.                         M_Menu_LanConfig_f ();
  1014.                         break;
  1015.  
  1016.                 case 3:
  1017.                         M_Menu_LanConfig_f ();
  1018.                         break;
  1019.  
  1020.                 case 4:
  1021. // multiprotocol
  1022.                         break;
  1023.                 }
  1024.         }
  1025.  
  1026.         if (m_net_cursor == 0 && !serialAvailable)
  1027.                 goto again;
  1028.         if (m_net_cursor == 1 && !serialAvailable)
  1029.                 goto again;
  1030.         if (m_net_cursor == 2 && !ipxAvailable)
  1031.                 goto again;
  1032.         if (m_net_cursor == 3 && !tcpipAvailable)
  1033.                 goto again;
  1034. }
  1035.  
  1036. //=============================================================================
  1037. /* OPTIONS MENU */
  1038.  
  1039. #ifdef _WIN32
  1040. #define OPTIONS_ITEMS   14
  1041. #else
  1042. #define OPTIONS_ITEMS   13
  1043. #endif
  1044.  
  1045. #define SLIDER_RANGE    10
  1046.  
  1047. int             options_cursor;
  1048.  
  1049. void M_Menu_Options_f (void)
  1050. {
  1051.         key_dest = key_menu;
  1052.         m_state = m_options;
  1053.         m_entersound = true;
  1054.  
  1055. #ifdef _WIN32
  1056.         if ((options_cursor == 13) && (modestate != MS_WINDOWED))
  1057.         {
  1058.                 options_cursor = 0;
  1059.         }
  1060. #endif
  1061. }
  1062.  
  1063.  
  1064. void M_AdjustSliders (int dir)
  1065. {
  1066.         S_LocalSound ("misc/menu3.wav");
  1067.  
  1068.         switch (options_cursor)
  1069.         {
  1070.         case 3: // screen size
  1071.                 scr_viewsize.value += dir * 10;
  1072.                 if (scr_viewsize.value < 30)
  1073.                         scr_viewsize.value = 30;
  1074.                 if (scr_viewsize.value > 120)
  1075.                         scr_viewsize.value = 120;
  1076.                 Cvar_SetValue ("viewsize", scr_viewsize.value);
  1077.                 break;
  1078.         case 4: // gamma
  1079.                 v_gamma.value -= dir * 0.05;
  1080.                 if (v_gamma.value < 0.5)
  1081.                         v_gamma.value = 0.5;
  1082.                 if (v_gamma.value > 1)
  1083.                         v_gamma.value = 1;
  1084.                 Cvar_SetValue ("gamma", v_gamma.value);
  1085.                 break;
  1086.         case 5: // mouse speed
  1087.                 sensitivity.value += dir * 0.5;
  1088.                 if (sensitivity.value < 1)
  1089.                         sensitivity.value = 1;
  1090.                 if (sensitivity.value > 11)
  1091.                         sensitivity.value = 11;
  1092.                 Cvar_SetValue ("sensitivity", sensitivity.value);
  1093.                 break;
  1094.         case 6: // music volume
  1095. #ifdef _WIN32
  1096.                 bgmvolume.value += dir * 1.0;
  1097. #else
  1098.                 bgmvolume.value += dir * 0.1;
  1099. #endif
  1100.                 if (bgmvolume.value < 0)
  1101.                         bgmvolume.value = 0;
  1102.                 if (bgmvolume.value > 1)
  1103.                         bgmvolume.value = 1;
  1104.                 Cvar_SetValue ("bgmvolume", bgmvolume.value);
  1105.                 break;
  1106.         case 7: // sfx volume
  1107.                 volume.value += dir * 0.1;
  1108.                 if (volume.value < 0)
  1109.                         volume.value = 0;
  1110.                 if (volume.value > 1)
  1111.                         volume.value = 1;
  1112.                 Cvar_SetValue ("volume", volume.value);
  1113.                 break;
  1114.  
  1115.         case 8: // allways run
  1116.                 if (cl_forwardspeed.value > 200)
  1117.                 {
  1118.                         Cvar_SetValue ("cl_forwardspeed", 200);
  1119.                         Cvar_SetValue ("cl_backspeed", 200);
  1120.                 }
  1121.                 else
  1122.                 {
  1123.                         Cvar_SetValue ("cl_forwardspeed", 400);
  1124.                         Cvar_SetValue ("cl_backspeed", 400);
  1125.                 }
  1126.                 break;
  1127.  
  1128.         case 9: // invert mouse
  1129.                 Cvar_SetValue ("m_pitch", -m_pitch.value);
  1130.                 break;
  1131.  
  1132.         case 10:        // lookspring
  1133.                 Cvar_SetValue ("lookspring", !lookspring.value);
  1134.                 break;
  1135.  
  1136.         case 11:        // lookstrafe
  1137.                 Cvar_SetValue ("lookstrafe", !lookstrafe.value);
  1138.                 break;
  1139.  
  1140. #ifdef _WIN32
  1141.         case 13:        // _windowed_mouse
  1142.                 Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
  1143.                 break;
  1144. #endif
  1145.         }
  1146. }
  1147.  
  1148.  
  1149. void M_DrawSlider (int x, int y, float range)
  1150. {
  1151.         int     i;
  1152.  
  1153.         if (range < 0)
  1154.                 range = 0;
  1155.         if (range > 1)
  1156.                 range = 1;
  1157.         M_DrawCharacter (x-8, y, 128);
  1158.         for (i=0 ; i<SLIDER_RANGE ; i++)
  1159.                 M_DrawCharacter (x + i*8, y, 129);
  1160.         M_DrawCharacter (x+i*8, y, 130);
  1161.         M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
  1162. }
  1163.  
  1164. void M_DrawCheckbox (int x, int y, int on)
  1165. {
  1166. #if 0
  1167.         if (on)
  1168.                 M_DrawCharacter (x, y, 131);
  1169.         else
  1170.                 M_DrawCharacter (x, y, 129);
  1171. #endif
  1172.         if (on)
  1173.                 M_Print (x, y, "on");
  1174.         else
  1175.                 M_Print (x, y, "off");
  1176. }
  1177.  
  1178. void M_Options_Draw (void)
  1179. {
  1180.         float           r;
  1181.         qpic_t  *p;
  1182.  
  1183.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  1184.         p = Draw_CachePic ("gfx/p_option.lmp");
  1185.         M_DrawPic ( (320-p->width)/2, 4, p);
  1186.  
  1187.         M_Print (16, 32, "    Customize controls");
  1188.         M_Print (16, 40, "         Go to console");
  1189.         M_Print (16, 48, "     Reset to defaults");
  1190.  
  1191.         M_Print (16, 56, "           Screen size");
  1192.         r = (scr_viewsize.value - 30) / (120 - 30);
  1193.         M_DrawSlider (220, 56, r);
  1194.  
  1195.         M_Print (16, 64, "            Brightness");
  1196.         r = (1.0 - v_gamma.value) / 0.5;
  1197.         M_DrawSlider (220, 64, r);
  1198.  
  1199.         M_Print (16, 72, "           Mouse Speed");
  1200.         r = (sensitivity.value - 1)/10;
  1201.         M_DrawSlider (220, 72, r);
  1202.  
  1203.         M_Print (16, 80, "       CD Music Volume");
  1204.         r = bgmvolume.value;
  1205.         M_DrawSlider (220, 80, r);
  1206.  
  1207.         M_Print (16, 88, "          Sound Volume");
  1208.         r = volume.value;
  1209.         M_DrawSlider (220, 88, r);
  1210.  
  1211.         M_Print (16, 96,  "            Always Run");
  1212.         M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
  1213.  
  1214.         M_Print (16, 104, "          Invert Mouse");
  1215.         M_DrawCheckbox (220, 104, m_pitch.value < 0);
  1216.  
  1217.         M_Print (16, 112, "            Lookspring");
  1218.         M_DrawCheckbox (220, 112, lookspring.value);
  1219.  
  1220.         M_Print (16, 120, "            Lookstrafe");
  1221.         M_DrawCheckbox (220, 120, lookstrafe.value);
  1222.  
  1223.         if (vid_menudrawfn)
  1224.                 M_Print (16, 128, "         Video Options");
  1225.  
  1226. #ifdef _WIN32
  1227.         if (modestate == MS_WINDOWED)
  1228.         {
  1229.                 M_Print (16, 136, "             Use Mouse");
  1230.                 M_DrawCheckbox (220, 136, _windowed_mouse.value);
  1231.         }
  1232. #endif
  1233.  
  1234. // cursor
  1235.         M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
  1236. }
  1237.  
  1238.  
  1239. void M_Options_Key (int k)
  1240. {
  1241.         switch (k)
  1242.         {
  1243.         case K_ESCAPE:
  1244.                 M_Menu_Main_f ();
  1245.                 break;
  1246.  
  1247.         case K_ENTER:
  1248.                 m_entersound = true;
  1249.                 switch (options_cursor)
  1250.                 {
  1251.                 case 0:
  1252.                         M_Menu_Keys_f ();
  1253.                         break;
  1254.                 case 1:
  1255.                         m_state = m_none;
  1256.                         Con_ToggleConsole_f ();
  1257.                         break;
  1258.                 case 2:
  1259.                         Cbuf_AddText ("exec default.cfg\n");
  1260.                         break;
  1261.                 case 12:
  1262.                         M_Menu_Video_f ();
  1263.                         break;
  1264.                 default:
  1265.                         M_AdjustSliders (1);
  1266.                         break;
  1267.                 }
  1268.                 return;
  1269.  
  1270.         case K_UPARROW:
  1271.                 S_LocalSound ("misc/menu1.wav");
  1272.                 options_cursor--;
  1273.                 if (options_cursor < 0)
  1274.                         options_cursor = OPTIONS_ITEMS-1;
  1275.                 break;
  1276.  
  1277.         case K_DOWNARROW:
  1278.                 S_LocalSound ("misc/menu1.wav");
  1279.                 options_cursor++;
  1280.                 if (options_cursor >= OPTIONS_ITEMS)
  1281.                         options_cursor = 0;
  1282.                 break;
  1283.  
  1284.         case K_LEFTARROW:
  1285.                 M_AdjustSliders (-1);
  1286.                 break;
  1287.  
  1288.         case K_RIGHTARROW:
  1289.                 M_AdjustSliders (1);
  1290.                 break;
  1291.         }
  1292.  
  1293.         if (options_cursor == 12 && vid_menudrawfn == NULL)
  1294.         {
  1295.                 if (k == K_UPARROW)
  1296.                         options_cursor = 11;
  1297.                 else
  1298.                         options_cursor = 0;
  1299.         }
  1300.  
  1301. #ifdef _WIN32
  1302.         if ((options_cursor == 13) && (modestate != MS_WINDOWED))
  1303.         {
  1304.                 if (k == K_UPARROW)
  1305.                         options_cursor = 12;
  1306.                 else
  1307.                         options_cursor = 0;
  1308.         }
  1309. #endif
  1310. }
  1311.  
  1312. //=============================================================================
  1313. /* KEYS MENU */
  1314.  
  1315. char *bindnames[][2] =
  1316. {
  1317. {"+attack",             "attack"},
  1318. {"impulse 10",          "change weapon"},
  1319. {"+jump",                       "jump / swim up"},
  1320. {"+forward",            "walk forward"},
  1321. {"+back",                       "backpedal"},
  1322. {"+left",                       "turn left"},
  1323. {"+right",                      "turn right"},
  1324. {"+speed",                      "run"},
  1325. {"+moveleft",           "step left"},
  1326. {"+moveright",          "step right"},
  1327. {"+strafe",             "sidestep"},
  1328. {"+lookup",             "look up"},
  1329. {"+lookdown",           "look down"},
  1330. {"centerview",          "center view"},
  1331. {"+mlook",                      "mouse look"},
  1332. {"+klook",                      "keyboard look"},
  1333. {"+moveup",                     "swim up"},
  1334. {"+movedown",           "swim down"}
  1335. };
  1336.  
  1337. #define NUMCOMMANDS     (sizeof(bindnames)/sizeof(bindnames[0]))
  1338.  
  1339. int             keys_cursor;
  1340. int             bind_grab;
  1341.  
  1342. void M_Menu_Keys_f (void)
  1343. {
  1344.         key_dest = key_menu;
  1345.         m_state = m_keys;
  1346.         m_entersound = true;
  1347. }
  1348.  
  1349.  
  1350. void M_FindKeysForCommand (char *command, int *twokeys)
  1351. {
  1352.         int             count;
  1353.         int             j;
  1354.         int             l;
  1355.         char    *b;
  1356.  
  1357.         twokeys[0] = twokeys[1] = -1;
  1358.         l = strlen(command);
  1359.         count = 0;
  1360.  
  1361.         for (j=0 ; j<256 ; j++)
  1362.         {
  1363.                 b = keybindings[j];
  1364.                 if (!b)
  1365.                         continue;
  1366.                 if (!strncmp (b, command, l) )
  1367.                 {
  1368.                         twokeys[count] = j;
  1369.                         count++;
  1370.                         if (count == 2)
  1371.                                 break;
  1372.                 }
  1373.         }
  1374. }
  1375.  
  1376. void M_UnbindCommand (char *command)
  1377. {
  1378.         int             j;
  1379.         int             l;
  1380.         char    *b;
  1381.  
  1382.         l = strlen(command);
  1383.  
  1384.         for (j=0 ; j<256 ; j++)
  1385.         {
  1386.                 b = keybindings[j];
  1387.                 if (!b)
  1388.                         continue;
  1389.                 if (!strncmp (b, command, l) )
  1390.                         Key_SetBinding (j, "");
  1391.         }
  1392. }
  1393.  
  1394.  
  1395. void M_Keys_Draw (void)
  1396. {
  1397.         int             i, l;
  1398.         int             keys[2];
  1399.         char    *name;
  1400.         int             x, y;
  1401.         qpic_t  *p;
  1402.  
  1403.         p = Draw_CachePic ("gfx/ttl_cstm.lmp");
  1404.         M_DrawPic ( (320-p->width)/2, 4, p);
  1405.  
  1406.         if (bind_grab)
  1407.                 M_Print (12, 32, "Press a key or button for this action");
  1408.         else
  1409.                 M_Print (18, 32, "Enter to change, backspace to clear");
  1410.  
  1411. // search for known bindings
  1412.         for (i=0 ; i<NUMCOMMANDS ; i++)
  1413.         {
  1414.                 y = 48 + 8*i;
  1415.  
  1416.                 M_Print (16, y, bindnames[i][1]);
  1417.  
  1418.                 l = strlen (bindnames[i][0]);
  1419.  
  1420.                 M_FindKeysForCommand (bindnames[i][0], keys);
  1421.  
  1422.                 if (keys[0] == -1)
  1423.                 {
  1424.                         M_Print (140, y, "???");
  1425.                 }
  1426.                 else
  1427.                 {
  1428.                         name = Key_KeynumToString (keys[0]);
  1429.                         M_Print (140, y, name);
  1430.                         x = strlen(name) * 8;
  1431.                         if (keys[1] != -1)
  1432.                         {
  1433.                                 M_Print (140 + x + 8, y, "or");
  1434.                                 M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
  1435.                         }
  1436.                 }
  1437.         }
  1438.  
  1439.         if (bind_grab)
  1440.                 M_DrawCharacter (130, 48 + keys_cursor*8, '=');
  1441.         else
  1442.                 M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
  1443. }
  1444.  
  1445.  
  1446. void M_Keys_Key (int k)
  1447. {
  1448.         char    cmd[80];
  1449.         int             keys[2];
  1450.  
  1451.         if (bind_grab)
  1452.         {       // defining a key
  1453.                 S_LocalSound ("misc/menu1.wav");
  1454.                 if (k == K_ESCAPE)
  1455.                 {
  1456.                         bind_grab = false;
  1457.                 }
  1458.                 else if (k != '`')
  1459.                 {
  1460.                         sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
  1461.                         Cbuf_InsertText (cmd);
  1462.                 }
  1463.  
  1464.                 bind_grab = false;
  1465.                 return;
  1466.         }
  1467.  
  1468.         switch (k)
  1469.         {
  1470.         case K_ESCAPE:
  1471.                 M_Menu_Options_f ();
  1472.                 break;
  1473.  
  1474.         case K_LEFTARROW:
  1475.         case K_UPARROW:
  1476.                 S_LocalSound ("misc/menu1.wav");
  1477.                 keys_cursor--;
  1478.                 if (keys_cursor < 0)
  1479.                         keys_cursor = NUMCOMMANDS-1;
  1480.                 break;
  1481.  
  1482.         case K_DOWNARROW:
  1483.         case K_RIGHTARROW:
  1484.                 S_LocalSound ("misc/menu1.wav");
  1485.                 keys_cursor++;
  1486.                 if (keys_cursor >= NUMCOMMANDS)
  1487.                         keys_cursor = 0;
  1488.                 break;
  1489.  
  1490.         case K_ENTER:           // go into bind mode
  1491.                 M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
  1492.                 S_LocalSound ("misc/menu2.wav");
  1493.                 if (keys[1] != -1)
  1494.                         M_UnbindCommand (bindnames[keys_cursor][0]);
  1495.                 bind_grab = true;
  1496.                 break;
  1497.  
  1498.         case K_BACKSPACE:               // delete bindings
  1499.         case K_DEL:                             // delete bindings
  1500.                 S_LocalSound ("misc/menu2.wav");
  1501.                 M_UnbindCommand (bindnames[keys_cursor][0]);
  1502.                 break;
  1503.         }
  1504. }
  1505.  
  1506. //=============================================================================
  1507. /* VIDEO MENU */
  1508.  
  1509. void M_Menu_Video_f (void)
  1510. {
  1511.         key_dest = key_menu;
  1512.         m_state = m_video;
  1513.         m_entersound = true;
  1514. }
  1515.  
  1516.  
  1517. void M_Video_Draw (void)
  1518. {
  1519.         (*vid_menudrawfn) ();
  1520. }
  1521.  
  1522.  
  1523. void M_Video_Key (int key)
  1524. {
  1525.         (*vid_menukeyfn) (key);
  1526. }
  1527.  
  1528. //=============================================================================
  1529. /* HELP MENU */
  1530.  
  1531. int             help_page;
  1532. #define NUM_HELP_PAGES  6
  1533.  
  1534.  
  1535. void M_Menu_Help_f (void)
  1536. {
  1537.         key_dest = key_menu;
  1538.         m_state = m_help;
  1539.         m_entersound = true;
  1540.         help_page = 0;
  1541. }
  1542.  
  1543.  
  1544.  
  1545. void M_Help_Draw (void)
  1546. {
  1547.         M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
  1548. }
  1549.  
  1550.  
  1551. void M_Help_Key (int key)
  1552. {
  1553.         switch (key)
  1554.         {
  1555.         case K_ESCAPE:
  1556.                 M_Menu_Main_f ();
  1557.                 break;
  1558.  
  1559.         case K_UPARROW:
  1560.         case K_RIGHTARROW:
  1561.                 m_entersound = true;
  1562.                 if (++help_page >= NUM_HELP_PAGES)
  1563.                         help_page = 0;
  1564.                 break;
  1565.  
  1566.         case K_DOWNARROW:
  1567.         case K_LEFTARROW:
  1568.                 m_entersound = true;
  1569.                 if (--help_page < 0)
  1570.                         help_page = NUM_HELP_PAGES-1;
  1571.                 break;
  1572.         }
  1573.  
  1574. }
  1575.  
  1576. //=============================================================================
  1577. /* QUIT MENU */
  1578.  
  1579. int             msgNumber;
  1580. int             m_quit_prevstate;
  1581. qboolean        wasInMenus;
  1582.  
  1583. #ifndef _WIN32
  1584. char *quitMessage [] =
  1585. {
  1586. /* .........1.........2.... */
  1587.   "  Are you gonna quit    ",
  1588.   "  this game just like   ",
  1589.   "   everything else?     ",
  1590.   "                        ",
  1591.  
  1592.   " Milord, methinks that  ",
  1593.   "   thou art a lowly     ",
  1594.   " quitter. Is this true? ",
  1595.   "                        ",
  1596.  
  1597.   " Do I need to bust your ",
  1598.   "  face open for trying  ",
  1599.   "        to quit?        ",
  1600.   "                        ",
  1601.  
  1602.   " Man, I oughta smack you",
  1603.   "   for trying to quit!  ",
  1604.   "     Press Y to get     ",
  1605.   "      smacked out.      ",
  1606.  
  1607.   " Press Y to quit like a ",
  1608.   "   big loser in life.   ",
  1609.   "  Press N to stay proud ",
  1610.   "    and successful!     ",
  1611.  
  1612.   "   If you press Y to    ",
  1613.   "  quit, I will summon   ",
  1614.   "  Satan all over your   ",
  1615.   "      hard drive!       ",
  1616.  
  1617.   "  Um, Asmodeus dislikes ",
  1618.   " his children trying to ",
  1619.   " quit. Press Y to return",
  1620.   "   to your Tinkertoys.  ",
  1621.  
  1622.   "  If you quit now, I'll ",
  1623.   "  throw a blanket-party ",
  1624.   "   for you next time!   ",
  1625.   "                        "
  1626. };
  1627. #endif
  1628.  
  1629. void M_Menu_Quit_f (void)
  1630. {
  1631.         if (m_state == m_quit)
  1632.                 return;
  1633.         wasInMenus = (key_dest == key_menu);
  1634.         key_dest = key_menu;
  1635.         m_quit_prevstate = m_state;
  1636.         m_state = m_quit;
  1637.         m_entersound = true;
  1638.         msgNumber = rand()&7;
  1639. }
  1640.  
  1641.  
  1642. void M_Quit_Key (int key)
  1643. {
  1644.         switch (key)
  1645.         {
  1646.         case K_ESCAPE:
  1647.         case 'n':
  1648.         case 'N':
  1649.                 if (wasInMenus)
  1650.                 {
  1651.                         m_state = m_quit_prevstate;
  1652.                         m_entersound = true;
  1653.                 }
  1654.                 else
  1655.                 {
  1656.                         key_dest = key_game;
  1657.                         m_state = m_none;
  1658.                 }
  1659.                 break;
  1660.  
  1661.         case 'Y':
  1662.         case 'y':
  1663.                 key_dest = key_console;
  1664.                 Host_Quit_f ();
  1665.                 break;
  1666.  
  1667.         default:
  1668.                 break;
  1669.         }
  1670.  
  1671. }
  1672.  
  1673.  
  1674. void M_Quit_Draw (void)
  1675. {
  1676.         if (wasInMenus)
  1677.         {
  1678.                 m_state = m_quit_prevstate;
  1679.                 m_recursiveDraw = true;
  1680.                 M_Draw ();
  1681.                 m_state = m_quit;
  1682.         }
  1683.  
  1684. #ifdef _WIN32
  1685.         M_DrawTextBox (0, 0, 38, 23);
  1686.         M_PrintWhite (16, 12,  "  Quake version 1.09 by id Software\n\n");
  1687.         M_PrintWhite (16, 28,  "Programming        Art \n");
  1688.         M_Print (16, 36,  " John Carmack       Adrian Carmack\n");
  1689.         M_Print (16, 44,  " Michael Abrash     Kevin Cloud\n");
  1690.         M_Print (16, 52,  " John Cash          Paul Steed\n");
  1691.         M_Print (16, 60,  " Dave 'Zoid' Kirsch\n");
  1692.         M_PrintWhite (16, 68,  "Design             Biz\n");
  1693.         M_Print (16, 76,  " John Romero        Jay Wilbur\n");
  1694.         M_Print (16, 84,  " Sandy Petersen     Mike Wilson\n");
  1695.         M_Print (16, 92,  " American McGee     Donna Jackson\n");
  1696.         M_Print (16, 100,  " Tim Willits        Todd Hollenshead\n");
  1697.         M_PrintWhite (16, 108, "Support            Projects\n");
  1698.         M_Print (16, 116, " Barrett Alexander  Shawn Green\n");
  1699.         M_PrintWhite (16, 124, "Sound Effects\n");
  1700.         M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
  1701.         M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
  1702.         M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
  1703.         M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
  1704.         M_PrintWhite (16, 164, "registered trademark licensed to\n");
  1705.         M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
  1706.         M_PrintWhite (16, 180, "reserved. Press y to exit\n");
  1707. #else
  1708.         M_DrawTextBox (56, 76, 24, 4);
  1709.         M_Print (64, 84,  quitMessage[msgNumber*4+0]);
  1710.         M_Print (64, 92,  quitMessage[msgNumber*4+1]);
  1711.         M_Print (64, 100, quitMessage[msgNumber*4+2]);
  1712.         M_Print (64, 108, quitMessage[msgNumber*4+3]);
  1713. #endif
  1714. }
  1715.  
  1716. //=============================================================================
  1717.  
  1718. /* SERIAL CONFIG MENU */
  1719.  
  1720. int             serialConfig_cursor;
  1721. int             serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
  1722. #define NUM_SERIALCONFIG_CMDS   6
  1723.  
  1724. static int ISA_uarts[]  = {0x3f8,0x2f8,0x3e8,0x2e8};
  1725. static int ISA_IRQs[]   = {4,3,4,3};
  1726. int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
  1727.  
  1728. int             serialConfig_comport;
  1729. int             serialConfig_irq ;
  1730. int             serialConfig_baud;
  1731. char    serialConfig_phone[16];
  1732.  
  1733. void M_Menu_SerialConfig_f (void)
  1734. {
  1735.         int             n;
  1736.         int             port;
  1737.         int             baudrate;
  1738.         qboolean        useModem;
  1739.  
  1740.         key_dest = key_menu;
  1741.         m_state = m_serialconfig;
  1742.         m_entersound = true;
  1743.         if (JoiningGame && SerialConfig)
  1744.                 serialConfig_cursor = 4;
  1745.         else
  1746.                 serialConfig_cursor = 5;
  1747.  
  1748.         (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
  1749.  
  1750.         // map uart's port to COMx
  1751.         for (n = 0; n < 4; n++)
  1752.                 if (ISA_uarts[n] == port)
  1753.                         break;
  1754.         if (n == 4)
  1755.         {
  1756.                 n = 0;
  1757.                 serialConfig_irq = 4;
  1758.         }
  1759.         serialConfig_comport = n + 1;
  1760.  
  1761.         // map baudrate to index
  1762.         for (n = 0; n < 6; n++)
  1763.                 if (serialConfig_baudrate[n] == baudrate)
  1764.                         break;
  1765.         if (n == 6)
  1766.                 n = 5;
  1767.         serialConfig_baud = n;
  1768.  
  1769.         m_return_onerror = false;
  1770.         m_return_reason[0] = 0;
  1771. }
  1772.  
  1773.  
  1774. void M_SerialConfig_Draw (void)
  1775. {
  1776.         qpic_t  *p;
  1777.         int             basex;
  1778.         char    *startJoin;
  1779.         char    *directModem;
  1780.  
  1781.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  1782.         p = Draw_CachePic ("gfx/p_multi.lmp");
  1783.         basex = (320-p->width)/2;
  1784.         M_DrawPic (basex, 4, p);
  1785.  
  1786.         if (StartingGame)
  1787.                 startJoin = "New Game";
  1788.         else
  1789.                 startJoin = "Join Game";
  1790.         if (SerialConfig)
  1791.                 directModem = "Modem";
  1792.         else
  1793.                 directModem = "Direct Connect";
  1794.         M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
  1795.         basex += 8;
  1796.  
  1797.         M_Print (basex, serialConfig_cursor_table[0], "Port");
  1798.         M_DrawTextBox (160, 40, 4, 1);
  1799.         M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
  1800.  
  1801.         M_Print (basex, serialConfig_cursor_table[1], "IRQ");
  1802.         M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
  1803.         M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
  1804.  
  1805.         M_Print (basex, serialConfig_cursor_table[2], "Baud");
  1806.         M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
  1807.         M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
  1808.  
  1809.         if (SerialConfig)
  1810.         {
  1811.                 M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
  1812.                 if (JoiningGame)
  1813.                 {
  1814.                         M_Print (basex, serialConfig_cursor_table[4], "Phone number");
  1815.                         M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
  1816.                         M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
  1817.                 }
  1818.         }
  1819.  
  1820.         if (JoiningGame)
  1821.         {
  1822.                 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
  1823.                 M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
  1824.         }
  1825.         else
  1826.         {
  1827.                 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
  1828.                 M_Print (basex+8, serialConfig_cursor_table[5], "OK");
  1829.         }
  1830.  
  1831.         M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
  1832.  
  1833.         if (serialConfig_cursor == 4)
  1834.                 M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
  1835.  
  1836.         if (*m_return_reason)
  1837.                 M_PrintWhite (basex, 148, m_return_reason);
  1838. }
  1839.  
  1840.  
  1841. void M_SerialConfig_Key (int key)
  1842. {
  1843.         int             l;
  1844.  
  1845.         switch (key)
  1846.         {
  1847.         case K_ESCAPE:
  1848.                 M_Menu_Net_f ();
  1849.                 break;
  1850.  
  1851.         case K_UPARROW:
  1852.                 S_LocalSound ("misc/menu1.wav");
  1853.                 serialConfig_cursor--;
  1854.                 if (serialConfig_cursor < 0)
  1855.                         serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
  1856.                 break;
  1857.  
  1858.         case K_DOWNARROW:
  1859.                 S_LocalSound ("misc/menu1.wav");
  1860.                 serialConfig_cursor++;
  1861.                 if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
  1862.                         serialConfig_cursor = 0;
  1863.                 break;
  1864.  
  1865.         case K_LEFTARROW:
  1866.                 if (serialConfig_cursor > 2)
  1867.                         break;
  1868.                 S_LocalSound ("misc/menu3.wav");
  1869.  
  1870.                 if (serialConfig_cursor == 0)
  1871.                 {
  1872.                         serialConfig_comport--;
  1873.                         if (serialConfig_comport == 0)
  1874.                                 serialConfig_comport = 4;
  1875.                         serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
  1876.                 }
  1877.  
  1878.                 if (serialConfig_cursor == 1)
  1879.                 {
  1880.                         serialConfig_irq--;
  1881.                         if (serialConfig_irq == 6)
  1882.                                 serialConfig_irq = 5;
  1883.                         if (serialConfig_irq == 1)
  1884.                                 serialConfig_irq = 7;
  1885.                 }
  1886.  
  1887.                 if (serialConfig_cursor == 2)
  1888.                 {
  1889.                         serialConfig_baud--;
  1890.                         if (serialConfig_baud < 0)
  1891.                                 serialConfig_baud = 5;
  1892.                 }
  1893.  
  1894.                 break;
  1895.  
  1896.         case K_RIGHTARROW:
  1897.                 if (serialConfig_cursor > 2)
  1898.                         break;
  1899. forward:
  1900.                 S_LocalSound ("misc/menu3.wav");
  1901.  
  1902.                 if (serialConfig_cursor == 0)
  1903.                 {
  1904.                         serialConfig_comport++;
  1905.                         if (serialConfig_comport > 4)
  1906.                                 serialConfig_comport = 1;
  1907.                         serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
  1908.                 }
  1909.  
  1910.                 if (serialConfig_cursor == 1)
  1911.                 {
  1912.                         serialConfig_irq++;
  1913.                         if (serialConfig_irq == 6)
  1914.                                 serialConfig_irq = 7;
  1915.                         if (serialConfig_irq == 8)
  1916.                                 serialConfig_irq = 2;
  1917.                 }
  1918.  
  1919.                 if (serialConfig_cursor == 2)
  1920.                 {
  1921.                         serialConfig_baud++;
  1922.                         if (serialConfig_baud > 5)
  1923.                                 serialConfig_baud = 0;
  1924.                 }
  1925.  
  1926.                 break;
  1927.  
  1928.         case K_ENTER:
  1929.                 if (serialConfig_cursor < 3)
  1930.                         goto forward;
  1931.  
  1932.                 m_entersound = true;
  1933.  
  1934.                 if (serialConfig_cursor == 3)
  1935.                 {
  1936.                         (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
  1937.  
  1938.                         M_Menu_ModemConfig_f ();
  1939.                         break;
  1940.                 }
  1941.  
  1942.                 if (serialConfig_cursor == 4)
  1943.                 {
  1944.                         serialConfig_cursor = 5;
  1945.                         break;
  1946.                 }
  1947.  
  1948.                 // serialConfig_cursor == 5 (OK/CONNECT)
  1949.                 (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
  1950.  
  1951.                 M_ConfigureNetSubsystem ();
  1952.  
  1953.                 if (StartingGame)
  1954.                 {
  1955.                         M_Menu_GameOptions_f ();
  1956.                         break;
  1957.                 }
  1958.  
  1959.                 m_return_state = m_state;
  1960.                 m_return_onerror = true;
  1961.                 key_dest = key_game;
  1962.                 m_state = m_none;
  1963.  
  1964.                 if (SerialConfig)
  1965.                         Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
  1966.                 else
  1967.                         Cbuf_AddText ("connect\n");
  1968.                 break;
  1969.  
  1970.         case K_BACKSPACE:
  1971.                 if (serialConfig_cursor == 4)
  1972.                 {
  1973.                         if (strlen(serialConfig_phone))
  1974.                                 serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
  1975.                 }
  1976.                 break;
  1977.  
  1978.         default:
  1979.                 if (key < 32 || key > 127)
  1980.                         break;
  1981.                 if (serialConfig_cursor == 4)
  1982.                 {
  1983.                         l = strlen(serialConfig_phone);
  1984.                         if (l < 15)
  1985.                         {
  1986.                                 serialConfig_phone[l+1] = 0;
  1987.                                 serialConfig_phone[l] = key;
  1988.                         }
  1989.                 }
  1990.         }
  1991.  
  1992.         if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
  1993.                 if (key == K_UPARROW)
  1994.                         serialConfig_cursor = 2;
  1995.                 else
  1996.                         serialConfig_cursor = 5;
  1997.  
  1998.         if (SerialConfig && StartingGame && serialConfig_cursor == 4)
  1999.                 if (key == K_UPARROW)
  2000.                         serialConfig_cursor = 3;
  2001.                 else
  2002.                         serialConfig_cursor = 5;
  2003. }
  2004.  
  2005. //=============================================================================
  2006. /* MODEM CONFIG MENU */
  2007.  
  2008. int             modemConfig_cursor;
  2009. int             modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
  2010. #define NUM_MODEMCONFIG_CMDS    5
  2011.  
  2012. char    modemConfig_dialing;
  2013. char    modemConfig_clear [16];
  2014. char    modemConfig_init [32];
  2015. char    modemConfig_hangup [16];
  2016.  
  2017. void M_Menu_ModemConfig_f (void)
  2018. {
  2019.         key_dest = key_menu;
  2020.         m_state = m_modemconfig;
  2021.         m_entersound = true;
  2022.         (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
  2023. }
  2024.  
  2025.  
  2026. void M_ModemConfig_Draw (void)
  2027. {
  2028.         qpic_t  *p;
  2029.         int             basex;
  2030.  
  2031.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2032.         p = Draw_CachePic ("gfx/p_multi.lmp");
  2033.         basex = (320-p->width)/2;
  2034.         M_DrawPic (basex, 4, p);
  2035.         basex += 8;
  2036.  
  2037.         if (modemConfig_dialing == 'P')
  2038.                 M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
  2039.         else
  2040.                 M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
  2041.  
  2042.         M_Print (basex, modemConfig_cursor_table[1], "Clear");
  2043.         M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
  2044.         M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
  2045.         if (modemConfig_cursor == 1)
  2046.                 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
  2047.  
  2048.         M_Print (basex, modemConfig_cursor_table[2], "Init");
  2049.         M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
  2050.         M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
  2051.         if (modemConfig_cursor == 2)
  2052.                 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
  2053.  
  2054.         M_Print (basex, modemConfig_cursor_table[3], "Hangup");
  2055.         M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
  2056.         M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
  2057.         if (modemConfig_cursor == 3)
  2058.                 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
  2059.  
  2060.         M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
  2061.         M_Print (basex+8, modemConfig_cursor_table[4], "OK");
  2062.  
  2063.         M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
  2064. }
  2065.  
  2066.  
  2067. void M_ModemConfig_Key (int key)
  2068. {
  2069.         int             l;
  2070.  
  2071.         switch (key)
  2072.         {
  2073.         case K_ESCAPE:
  2074.                 M_Menu_SerialConfig_f ();
  2075.                 break;
  2076.  
  2077.         case K_UPARROW:
  2078.                 S_LocalSound ("misc/menu1.wav");
  2079.                 modemConfig_cursor--;
  2080.                 if (modemConfig_cursor < 0)
  2081.                         modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
  2082.                 break;
  2083.  
  2084.         case K_DOWNARROW:
  2085.                 S_LocalSound ("misc/menu1.wav");
  2086.                 modemConfig_cursor++;
  2087.                 if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
  2088.                         modemConfig_cursor = 0;
  2089.                 break;
  2090.  
  2091.         case K_LEFTARROW:
  2092.         case K_RIGHTARROW:
  2093.                 if (modemConfig_cursor == 0)
  2094.                 {
  2095.                         if (modemConfig_dialing == 'P')
  2096.                                 modemConfig_dialing = 'T';
  2097.                         else
  2098.                                 modemConfig_dialing = 'P';
  2099.                         S_LocalSound ("misc/menu1.wav");
  2100.                 }
  2101.                 break;
  2102.  
  2103.         case K_ENTER:
  2104.                 if (modemConfig_cursor == 0)
  2105.                 {
  2106.                         if (modemConfig_dialing == 'P')
  2107.                                 modemConfig_dialing = 'T';
  2108.                         else
  2109.                                 modemConfig_dialing = 'P';
  2110.                         m_entersound = true;
  2111.                 }
  2112.  
  2113.                 if (modemConfig_cursor == 4)
  2114.                 {
  2115.                         (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
  2116.                         m_entersound = true;
  2117.                         M_Menu_SerialConfig_f ();
  2118.                 }
  2119.                 break;
  2120.  
  2121.         case K_BACKSPACE:
  2122.                 if (modemConfig_cursor == 1)
  2123.                 {
  2124.                         if (strlen(modemConfig_clear))
  2125.                                 modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
  2126.                 }
  2127.  
  2128.                 if (modemConfig_cursor == 2)
  2129.                 {
  2130.                         if (strlen(modemConfig_init))
  2131.                                 modemConfig_init[strlen(modemConfig_init)-1] = 0;
  2132.                 }
  2133.  
  2134.                 if (modemConfig_cursor == 3)
  2135.                 {
  2136.                         if (strlen(modemConfig_hangup))
  2137.                                 modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
  2138.                 }
  2139.                 break;
  2140.  
  2141.         default:
  2142.                 if (key < 32 || key > 127)
  2143.                         break;
  2144.  
  2145.                 if (modemConfig_cursor == 1)
  2146.                 {
  2147.                         l = strlen(modemConfig_clear);
  2148.                         if (l < 15)
  2149.                         {
  2150.                                 modemConfig_clear[l+1] = 0;
  2151.                                 modemConfig_clear[l] = key;
  2152.                         }
  2153.                 }
  2154.  
  2155.                 if (modemConfig_cursor == 2)
  2156.                 {
  2157.                         l = strlen(modemConfig_init);
  2158.                         if (l < 29)
  2159.                         {
  2160.                                 modemConfig_init[l+1] = 0;
  2161.                                 modemConfig_init[l] = key;
  2162.                         }
  2163.                 }
  2164.  
  2165.                 if (modemConfig_cursor == 3)
  2166.                 {
  2167.                         l = strlen(modemConfig_hangup);
  2168.                         if (l < 15)
  2169.                         {
  2170.                                 modemConfig_hangup[l+1] = 0;
  2171.                                 modemConfig_hangup[l] = key;
  2172.                         }
  2173.                 }
  2174.         }
  2175. }
  2176.  
  2177. //=============================================================================
  2178. /* LAN CONFIG MENU */
  2179.  
  2180. int             lanConfig_cursor = -1;
  2181. int             lanConfig_cursor_table [] = {72, 92, 124};
  2182. #define NUM_LANCONFIG_CMDS      3
  2183.  
  2184. int     lanConfig_port;
  2185. char    lanConfig_portname[6];
  2186. char    lanConfig_joinname[22];
  2187.  
  2188. void M_Menu_LanConfig_f (void)
  2189. {
  2190.         key_dest = key_menu;
  2191.         m_state = m_lanconfig;
  2192.         m_entersound = true;
  2193.         if (lanConfig_cursor == -1)
  2194.         {
  2195.                 if (JoiningGame && TCPIPConfig)
  2196.                         lanConfig_cursor = 2;
  2197.                 else
  2198.                         lanConfig_cursor = 1;
  2199.         }
  2200.         if (StartingGame && lanConfig_cursor == 2)
  2201.                 lanConfig_cursor = 1;
  2202.         lanConfig_port = DEFAULTnet_hostport;
  2203.         sprintf(lanConfig_portname, "%u", lanConfig_port);
  2204.  
  2205.         m_return_onerror = false;
  2206.         m_return_reason[0] = 0;
  2207. }
  2208.  
  2209.  
  2210. void M_LanConfig_Draw (void)
  2211. {
  2212.         qpic_t  *p;
  2213.         int             basex;
  2214.         char    *startJoin;
  2215.         char    *protocol;
  2216.  
  2217.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2218.         p = Draw_CachePic ("gfx/p_multi.lmp");
  2219.         basex = (320-p->width)/2;
  2220.         M_DrawPic (basex, 4, p);
  2221.  
  2222.         if (StartingGame)
  2223.                 startJoin = "New Game";
  2224.         else
  2225.                 startJoin = "Join Game";
  2226.         if (IPXConfig)
  2227.                 protocol = "IPX";
  2228.         else
  2229.                 protocol = "TCP/IP";
  2230.         M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
  2231.         basex += 8;
  2232.  
  2233.         M_Print (basex, 52, "Address:");
  2234.         if (IPXConfig)
  2235.                 M_Print (basex+9*8, 52, my_ipx_address);
  2236.         else
  2237.                 M_Print (basex+9*8, 52, my_tcpip_address);
  2238.  
  2239.         M_Print (basex, lanConfig_cursor_table[0], "Port");
  2240.         M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
  2241.         M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
  2242.  
  2243.         if (JoiningGame)
  2244.         {
  2245.                 M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
  2246.                 M_Print (basex, 108, "Join game at:");
  2247.                 M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
  2248.                 M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
  2249.         }
  2250.         else
  2251.         {
  2252.                 M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
  2253.                 M_Print (basex+8, lanConfig_cursor_table[1], "OK");
  2254.         }
  2255.  
  2256.         M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
  2257.  
  2258.         if (lanConfig_cursor == 0)
  2259.                 M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
  2260.  
  2261.         if (lanConfig_cursor == 2)
  2262.                 M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
  2263.  
  2264.         if (*m_return_reason)
  2265.                 M_PrintWhite (basex, 148, m_return_reason);
  2266. }
  2267.  
  2268.  
  2269. void M_LanConfig_Key (int key)
  2270. {
  2271.         int             l;
  2272.  
  2273.         switch (key)
  2274.         {
  2275.         case K_ESCAPE:
  2276.                 M_Menu_Net_f ();
  2277.                 break;
  2278.  
  2279.         case K_UPARROW:
  2280.                 S_LocalSound ("misc/menu1.wav");
  2281.                 lanConfig_cursor--;
  2282.                 if (lanConfig_cursor < 0)
  2283.                         lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
  2284.                 break;
  2285.  
  2286.         case K_DOWNARROW:
  2287.                 S_LocalSound ("misc/menu1.wav");
  2288.                 lanConfig_cursor++;
  2289.                 if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
  2290.                         lanConfig_cursor = 0;
  2291.                 break;
  2292.  
  2293.         case K_ENTER:
  2294.                 if (lanConfig_cursor == 0)
  2295.                         break;
  2296.  
  2297.                 m_entersound = true;
  2298.  
  2299.                 M_ConfigureNetSubsystem ();
  2300.  
  2301.                 if (lanConfig_cursor == 1)
  2302.                 {
  2303.                         if (StartingGame)
  2304.                         {
  2305.                                 M_Menu_GameOptions_f ();
  2306.                                 break;
  2307.                         }
  2308.                         M_Menu_Search_f();
  2309.                         break;
  2310.                 }
  2311.  
  2312.                 if (lanConfig_cursor == 2)
  2313.                 {
  2314.                         m_return_state = m_state;
  2315.                         m_return_onerror = true;
  2316.                         key_dest = key_game;
  2317.                         m_state = m_none;
  2318.                         Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
  2319.                         break;
  2320.                 }
  2321.  
  2322.                 break;
  2323.  
  2324.         case K_BACKSPACE:
  2325.                 if (lanConfig_cursor == 0)
  2326.                 {
  2327.                         if (strlen(lanConfig_portname))
  2328.                                 lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
  2329.                 }
  2330.  
  2331.                 if (lanConfig_cursor == 2)
  2332.                 {
  2333.                         if (strlen(lanConfig_joinname))
  2334.                                 lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
  2335.                 }
  2336.                 break;
  2337.  
  2338.         default:
  2339.                 if (key < 32 || key > 127)
  2340.                         break;
  2341.  
  2342.                 if (lanConfig_cursor == 2)
  2343.                 {
  2344.                         l = strlen(lanConfig_joinname);
  2345.                         if (l < 21)
  2346.                         {
  2347.                                 lanConfig_joinname[l+1] = 0;
  2348.                                 lanConfig_joinname[l] = key;
  2349.                         }
  2350.                 }
  2351.  
  2352.                 if (key < '0' || key > '9')
  2353.                         break;
  2354.                 if (lanConfig_cursor == 0)
  2355.                 {
  2356.                         l = strlen(lanConfig_portname);
  2357.                         if (l < 5)
  2358.                         {
  2359.                                 lanConfig_portname[l+1] = 0;
  2360.                                 lanConfig_portname[l] = key;
  2361.                         }
  2362.                 }
  2363.         }
  2364.  
  2365.         if (StartingGame && lanConfig_cursor == 2)
  2366.                 if (key == K_UPARROW)
  2367.                         lanConfig_cursor = 1;
  2368.                 else
  2369.                         lanConfig_cursor = 0;
  2370.  
  2371.         l =  Q_atoi(lanConfig_portname);
  2372.         if (l > 65535)
  2373.                 l = lanConfig_port;
  2374.         else
  2375.                 lanConfig_port = l;
  2376.         sprintf(lanConfig_portname, "%u", lanConfig_port);
  2377. }
  2378.  
  2379. //=============================================================================
  2380. /* GAME OPTIONS MENU */
  2381.  
  2382. typedef struct
  2383. {
  2384.         char    *name;
  2385.         char    *description;
  2386. } level_t;
  2387.  
  2388. level_t         levels[] =
  2389. {
  2390.         {"start", "Entrance"},  // 0
  2391.  
  2392.         {"e1m1", "Slipgate Complex"},                           // 1
  2393.         {"e1m2", "Castle of the Damned"},
  2394.         {"e1m3", "The Necropolis"},
  2395.         {"e1m4", "The Grisly Grotto"},
  2396.         {"e1m5", "Gloom Keep"},
  2397.         {"e1m6", "The Door To Chthon"},
  2398.         {"e1m7", "The House of Chthon"},
  2399.         {"e1m8", "Ziggurat Vertigo"},
  2400.  
  2401.         {"e2m1", "The Installation"},                           // 9
  2402.         {"e2m2", "Ogre Citadel"},
  2403.         {"e2m3", "Crypt of Decay"},
  2404.         {"e2m4", "The Ebon Fortress"},
  2405.         {"e2m5", "The Wizard's Manse"},
  2406.         {"e2m6", "The Dismal Oubliette"},
  2407.         {"e2m7", "Underearth"},
  2408.  
  2409.         {"e3m1", "Termination Central"},                        // 16
  2410.         {"e3m2", "The Vaults of Zin"},
  2411.         {"e3m3", "The Tomb of Terror"},
  2412.         {"e3m4", "Satan's Dark Delight"},
  2413.         {"e3m5", "Wind Tunnels"},
  2414.         {"e3m6", "Chambers of Torment"},
  2415.         {"e3m7", "The Haunted Halls"},
  2416.  
  2417.         {"e4m1", "The Sewage System"},                          // 23
  2418.         {"e4m2", "The Tower of Despair"},
  2419.         {"e4m3", "The Elder God Shrine"},
  2420.         {"e4m4", "The Palace of Hate"},
  2421.         {"e4m5", "Hell's Atrium"},
  2422.         {"e4m6", "The Pain Maze"},
  2423.         {"e4m7", "Azure Agony"},
  2424.         {"e4m8", "The Nameless City"},
  2425.  
  2426.         {"end", "Shub-Niggurath's Pit"},                        // 31
  2427.  
  2428.         {"dm1", "Place of Two Deaths"},                         // 32
  2429.         {"dm2", "Claustrophobopolis"},
  2430.         {"dm3", "The Abandoned Base"},
  2431.         {"dm4", "The Bad Place"},
  2432.         {"dm5", "The Cistern"},
  2433.         {"dm6", "The Dark Zone"}
  2434. };
  2435.  
  2436. //MED 01/06/97 added hipnotic levels
  2437. level_t     hipnoticlevels[] =
  2438. {
  2439.    {"start", "Command HQ"},  // 0
  2440.  
  2441.    {"hip1m1", "The Pumping Station"},          // 1
  2442.    {"hip1m2", "Storage Facility"},
  2443.    {"hip1m3", "The Lost Mine"},
  2444.    {"hip1m4", "Research Facility"},
  2445.    {"hip1m5", "Military Complex"},
  2446.  
  2447.    {"hip2m1", "Ancient Realms"},          // 6
  2448.    {"hip2m2", "The Black Cathedral"},
  2449.    {"hip2m3", "The Catacombs"},
  2450.    {"hip2m4", "The Crypt"},
  2451.    {"hip2m5", "Mortum's Keep"},
  2452.    {"hip2m6", "The Gremlin's Domain"},
  2453.  
  2454.    {"hip3m1", "Tur Torment"},       // 12
  2455.    {"hip3m2", "Pandemonium"},
  2456.    {"hip3m3", "Limbo"},
  2457.    {"hip3m4", "The Gauntlet"},
  2458.  
  2459.    {"hipend", "Armagon's Lair"},       // 16
  2460.  
  2461.    {"hipdm1", "The Edge of Oblivion"}           // 17
  2462. };
  2463.  
  2464. //PGM 01/07/97 added rogue levels
  2465. //PGM 03/02/97 added dmatch level
  2466. level_t         roguelevels[] =
  2467. {
  2468.         {"start",       "Split Decision"},
  2469.         {"r1m1",        "Deviant's Domain"},
  2470.         {"r1m2",        "Dread Portal"},
  2471.         {"r1m3",        "Judgement Call"},
  2472.         {"r1m4",        "Cave of Death"},
  2473.         {"r1m5",        "Towers of Wrath"},
  2474.         {"r1m6",        "Temple of Pain"},
  2475.         {"r1m7",        "Tomb of the Overlord"},
  2476.         {"r2m1",        "Tempus Fugit"},
  2477.         {"r2m2",        "Elemental Fury I"},
  2478.         {"r2m3",        "Elemental Fury II"},
  2479.         {"r2m4",        "Curse of Osiris"},
  2480.         {"r2m5",        "Wizard's Keep"},
  2481.         {"r2m6",        "Blood Sacrifice"},
  2482.         {"r2m7",        "Last Bastion"},
  2483.         {"r2m8",        "Source of Evil"},
  2484.         {"ctf1",    "Division of Change"}
  2485. };
  2486.  
  2487. typedef struct
  2488. {
  2489.         char    *description;
  2490.         int             firstLevel;
  2491.         int             levels;
  2492. } episode_t;
  2493.  
  2494. episode_t       episodes[] =
  2495. {
  2496.         {"Welcome to Quake", 0, 1},
  2497.         {"Doomed Dimension", 1, 8},
  2498.         {"Realm of Black Magic", 9, 7},
  2499.         {"Netherworld", 16, 7},
  2500.         {"The Elder World", 23, 8},
  2501.         {"Final Level", 31, 1},
  2502.         {"Deathmatch Arena", 32, 6}
  2503. };
  2504.  
  2505. //MED 01/06/97  added hipnotic episodes
  2506. episode_t   hipnoticepisodes[] =
  2507. {
  2508.    {"Scourge of Armagon", 0, 1},
  2509.    {"Fortress of the Dead", 1, 5},
  2510.    {"Dominion of Darkness", 6, 6},
  2511.    {"The Rift", 12, 4},
  2512.    {"Final Level", 16, 1},
  2513.    {"Deathmatch Arena", 17, 1}
  2514. };
  2515.  
  2516. //PGM 01/07/97 added rogue episodes
  2517. //PGM 03/02/97 added dmatch episode
  2518. episode_t       rogueepisodes[] =
  2519. {
  2520.         {"Introduction", 0, 1},
  2521.         {"Hell's Fortress", 1, 7},
  2522.         {"Corridors of Time", 8, 8},
  2523.         {"Deathmatch Arena", 16, 1}
  2524. };
  2525.  
  2526. int     startepisode;
  2527. int     startlevel;
  2528. int maxplayers;
  2529. qboolean m_serverInfoMessage = false;
  2530. double m_serverInfoMessageTime;
  2531.  
  2532. void M_Menu_GameOptions_f (void)
  2533. {
  2534.         key_dest = key_menu;
  2535.         m_state = m_gameoptions;
  2536.         m_entersound = true;
  2537.         if (maxplayers == 0)
  2538.                 maxplayers = svs.maxclients;
  2539.         if (maxplayers < 2)
  2540.                 maxplayers = svs.maxclientslimit;
  2541. }
  2542.  
  2543.  
  2544. int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
  2545. #define NUM_GAMEOPTIONS 9
  2546. int             gameoptions_cursor;
  2547.  
  2548. void M_GameOptions_Draw (void)
  2549. {
  2550.         qpic_t  *p;
  2551.         int             x;
  2552.  
  2553.         M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2554.         p = Draw_CachePic ("gfx/p_multi.lmp");
  2555.         M_DrawPic ( (320-p->width)/2, 4, p);
  2556.  
  2557.         M_DrawTextBox (152, 32, 10, 1);
  2558.         M_Print (160, 40, "begin game");
  2559.  
  2560.         M_Print (0, 56, "      Max players");
  2561.         M_Print (160, 56, va("%i", maxplayers) );
  2562.  
  2563.         M_Print (0, 64, "        Game Type");
  2564.         if (coop.value)
  2565.                 M_Print (160, 64, "Cooperative");
  2566.         else
  2567.                 M_Print (160, 64, "Deathmatch");
  2568.  
  2569.         M_Print (0, 72, "        Teamplay");
  2570.         if (rogue)
  2571.         {
  2572.                 char *msg;
  2573.  
  2574.                 switch((int)teamplay.value)
  2575.                 {
  2576.                         case 1: msg = "No Friendly Fire"; break;
  2577.                         case 2: msg = "Friendly Fire"; break;
  2578.                         case 3: msg = "Tag"; break;
  2579.                         case 4: msg = "Capture the Flag"; break;
  2580.                         case 5: msg = "One Flag CTF"; break;
  2581.                         case 6: msg = "Three Team CTF"; break;
  2582.                         default: msg = "Off"; break;
  2583.                 }
  2584.                 M_Print (160, 72, msg);
  2585.         }
  2586.         else
  2587.         {
  2588.                 char *msg;
  2589.  
  2590.                 switch((int)teamplay.value)
  2591.                 {
  2592.                         case 1: msg = "No Friendly Fire"; break;
  2593.                         case 2: msg = "Friendly Fire"; break;
  2594.                         default: msg = "Off"; break;
  2595.                 }
  2596.                 M_Print (160, 72, msg);
  2597.         }
  2598.  
  2599.         M_Print (0, 80, "            Skill");
  2600.         if (skill.value == 0)
  2601.                 M_Print (160, 80, "Easy difficulty");
  2602.         else if (skill.value == 1)
  2603.                 M_Print (160, 80, "Normal difficulty");
  2604.         else if (skill.value == 2)
  2605.                 M_Print (160, 80, "Hard difficulty");
  2606.         else
  2607.                 M_Print (160, 80, "Nightmare difficulty");
  2608.  
  2609.         M_Print (0, 88, "       Frag Limit");
  2610.         if (fraglimit.value == 0)
  2611.                 M_Print (160, 88, "none");
  2612.         else
  2613.                 M_Print (160, 88, va("%i frags", (int)fraglimit.value));
  2614.  
  2615.         M_Print (0, 96, "       Time Limit");
  2616.         if (timelimit.value == 0)
  2617.                 M_Print (160, 96, "none");
  2618.         else
  2619.                 M_Print (160, 96, va("%i minutes", (int)timelimit.value));
  2620.  
  2621.         M_Print (0, 112, "         Episode");
  2622.    //MED 01/06/97 added hipnotic episodes
  2623.    if (hipnotic)
  2624.       M_Print (160, 112, hipnoticepisodes[startepisode].description);
  2625.    //PGM 01/07/97 added rogue episodes
  2626.    else if (rogue)
  2627.       M_Print (160, 112, rogueepisodes[startepisode].description);
  2628.    else
  2629.       M_Print (160, 112, episodes[startepisode].description);
  2630.  
  2631.         M_Print (0, 120, "           Level");
  2632.    //MED 01/06/97 added hipnotic episodes
  2633.    if (hipnotic)
  2634.    {
  2635.       M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
  2636.       M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
  2637.    }
  2638.    //PGM 01/07/97 added rogue episodes
  2639.    else if (rogue)
  2640.    {
  2641.       M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
  2642.       M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
  2643.    }
  2644.    else
  2645.    {
  2646.       M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
  2647.       M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
  2648.    }
  2649.  
  2650. // line cursor
  2651.         M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
  2652.  
  2653.         if (m_serverInfoMessage)
  2654.         {
  2655.                 if ((realtime - m_serverInfoMessageTime) < 5.0)
  2656.                 {
  2657.                         x = (320-26*8)/2;
  2658.                         M_DrawTextBox (x, 138, 24, 4);
  2659.                         x += 8;
  2660.                         M_Print (x, 146, "  More than 4 players   ");
  2661.                         M_Print (x, 154, " requires using command ");
  2662.                         M_Print (x, 162, "line parameters; please ");
  2663.                         M_Print (x, 170, "   see techinfo.txt.    ");
  2664.                 }
  2665.                 else
  2666.                 {
  2667.                         m_serverInfoMessage = false;
  2668.                 }
  2669.         }
  2670. }
  2671.  
  2672.  
  2673. void M_NetStart_Change (int dir)
  2674. {
  2675.         int count;
  2676.  
  2677.         switch (gameoptions_cursor)
  2678.         {
  2679.         case 1:
  2680.                 maxplayers += dir;
  2681.                 if (maxplayers > svs.maxclientslimit)
  2682.                 {
  2683.                         maxplayers = svs.maxclientslimit;
  2684.                         m_serverInfoMessage = true;
  2685.                         m_serverInfoMessageTime = realtime;
  2686.                 }
  2687.                 if (maxplayers < 2)
  2688.                         maxplayers = 2;
  2689.                 break;
  2690.  
  2691.         case 2:
  2692.                 Cvar_SetValue ("coop", coop.value ? 0 : 1);
  2693.                 break;
  2694.  
  2695.         case 3:
  2696.                 if (rogue)
  2697.                         count = 6;
  2698.                 else
  2699.                         count = 2;
  2700.  
  2701.                 Cvar_SetValue ("teamplay", teamplay.value + dir);
  2702.                 if (teamplay.value > count)
  2703.                         Cvar_SetValue ("teamplay", 0);
  2704.                 else if (teamplay.value < 0)
  2705.                         Cvar_SetValue ("teamplay", count);
  2706.                 break;
  2707.  
  2708.         case 4:
  2709.                 Cvar_SetValue ("skill", skill.value + dir);
  2710.                 if (skill.value > 3)
  2711.                         Cvar_SetValue ("skill", 0);
  2712.                 if (skill.value < 0)
  2713.                         Cvar_SetValue ("skill", 3);
  2714.                 break;
  2715.  
  2716.         case 5:
  2717.                 Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
  2718.                 if (fraglimit.value > 100)
  2719.                         Cvar_SetValue ("fraglimit", 0);
  2720.                 if (fraglimit.value < 0)
  2721.                         Cvar_SetValue ("fraglimit", 100);
  2722.                 break;
  2723.  
  2724.         case 6:
  2725.                 Cvar_SetValue ("timelimit", timelimit.value + dir*5);
  2726.                 if (timelimit.value > 60)
  2727.                         Cvar_SetValue ("timelimit", 0);
  2728.                 if (timelimit.value < 0)
  2729.                         Cvar_SetValue ("timelimit", 60);
  2730.                 break;
  2731.  
  2732.         case 7:
  2733.                 startepisode += dir;
  2734.         //MED 01/06/97 added hipnotic count
  2735.                 if (hipnotic)
  2736.                         count = 6;
  2737.         //PGM 01/07/97 added rogue count
  2738.         //PGM 03/02/97 added 1 for dmatch episode
  2739.                 else if (rogue)
  2740.                         count = 4;
  2741.                 else if (registered.value)
  2742.                         count = 7;
  2743.                 else
  2744.                         count = 2;
  2745.  
  2746.                 if (startepisode < 0)
  2747.                         startepisode = count - 1;
  2748.  
  2749.                 if (startepisode >= count)
  2750.                         startepisode = 0;
  2751.  
  2752.                 startlevel = 0;
  2753.                 break;
  2754.  
  2755.         case 8:
  2756.                 startlevel += dir;
  2757.     //MED 01/06/97 added hipnotic episodes
  2758.                 if (hipnotic)
  2759.                         count = hipnoticepisodes[startepisode].levels;
  2760.         //PGM 01/06/97 added hipnotic episodes
  2761.                 else if (rogue)
  2762.                         count = rogueepisodes[startepisode].levels;
  2763.                 else
  2764.                         count = episodes[startepisode].levels;
  2765.  
  2766.                 if (startlevel < 0)
  2767.                         startlevel = count - 1;
  2768.  
  2769.                 if (startlevel >= count)
  2770.                         startlevel = 0;
  2771.                 break;
  2772.         }
  2773. }
  2774.  
  2775. void M_GameOptions_Key (int key)
  2776. {
  2777.         switch (key)
  2778.         {
  2779.         case K_ESCAPE:
  2780.                 M_Menu_Net_f ();
  2781.                 break;
  2782.  
  2783.         case K_UPARROW:
  2784.                 S_LocalSound ("misc/menu1.wav");
  2785.                 gameoptions_cursor--;
  2786.                 if (gameoptions_cursor < 0)
  2787.                         gameoptions_cursor = NUM_GAMEOPTIONS-1;
  2788.                 break;
  2789.  
  2790.         case K_DOWNARROW:
  2791.                 S_LocalSound ("misc/menu1.wav");
  2792.                 gameoptions_cursor++;
  2793.                 if (gameoptions_cursor >= NUM_GAMEOPTIONS)
  2794.                         gameoptions_cursor = 0;
  2795.                 break;
  2796.  
  2797.         case K_LEFTARROW:
  2798.                 if (gameoptions_cursor == 0)
  2799.                         break;
  2800.                 S_LocalSound ("misc/menu3.wav");
  2801.                 M_NetStart_Change (-1);
  2802.                 break;
  2803.  
  2804.         case K_RIGHTARROW:
  2805.                 if (gameoptions_cursor == 0)
  2806.                         break;
  2807.                 S_LocalSound ("misc/menu3.wav");
  2808.                 M_NetStart_Change (1);
  2809.                 break;
  2810.  
  2811.         case K_ENTER:
  2812.                 S_LocalSound ("misc/menu2.wav");
  2813.                 if (gameoptions_cursor == 0)
  2814.                 {
  2815.                         if (sv.active)
  2816.                                 Cbuf_AddText ("disconnect\n");
  2817.                         Cbuf_AddText ("listen 0\n");    // so host_netport will be re-examined
  2818.                         Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
  2819.                         SCR_BeginLoadingPlaque ();
  2820.  
  2821.                         if (hipnotic)
  2822.                                 Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
  2823.                         else if (rogue)
  2824.                                 Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
  2825.                         else
  2826.                                 Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
  2827.  
  2828.                         return;
  2829.                 }
  2830.  
  2831.                 M_NetStart_Change (1);
  2832.                 break;
  2833.         }
  2834. }
  2835.  
  2836. //=============================================================================
  2837. /* SEARCH MENU */
  2838.  
  2839. qboolean        searchComplete = false;
  2840. double          searchCompleteTime;
  2841.  
  2842. void M_Menu_Search_f (void)
  2843. {
  2844.         key_dest = key_menu;
  2845.         m_state = m_search;
  2846.         m_entersound = false;
  2847.         slistSilent = true;
  2848.         slistLocal = false;
  2849.         searchComplete = false;
  2850.         NET_Slist_f();
  2851.  
  2852. }
  2853.  
  2854.  
  2855. void M_Search_Draw (void)
  2856. {
  2857.         qpic_t  *p;
  2858.         int x;
  2859.  
  2860.         p = Draw_CachePic ("gfx/p_multi.lmp");
  2861.         M_DrawPic ( (320-p->width)/2, 4, p);
  2862.         x = (320/2) - ((12*8)/2) + 4;
  2863.         M_DrawTextBox (x-8, 32, 12, 1);
  2864.         M_Print (x, 40, "Searching...");
  2865.  
  2866.         if(slistInProgress)
  2867.         {
  2868.                 NET_Poll();
  2869.                 return;
  2870.         }
  2871.  
  2872.         if (! searchComplete)
  2873.         {
  2874.                 searchComplete = true;
  2875.                 searchCompleteTime = realtime;
  2876.         }
  2877.  
  2878.         if (hostCacheCount)
  2879.         {
  2880.                 M_Menu_ServerList_f ();
  2881.                 return;
  2882.         }
  2883.  
  2884.         M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
  2885.         if ((realtime - searchCompleteTime) < 3.0)
  2886.                 return;
  2887.  
  2888.         M_Menu_LanConfig_f ();
  2889. }
  2890.  
  2891.  
  2892. void M_Search_Key (int key)
  2893. {
  2894. }
  2895.  
  2896. //=============================================================================
  2897. /* SLIST MENU */
  2898.  
  2899. int             slist_cursor;
  2900. qboolean slist_sorted;
  2901.  
  2902. void M_Menu_ServerList_f (void)
  2903. {
  2904.         key_dest = key_menu;
  2905.         m_state = m_slist;
  2906.         m_entersound = true;
  2907.         slist_cursor = 0;
  2908.         m_return_onerror = false;
  2909.         m_return_reason[0] = 0;
  2910.         slist_sorted = false;
  2911. }
  2912.  
  2913.  
  2914. void M_ServerList_Draw (void)
  2915. {
  2916.         int             n;
  2917.         char    string [64];
  2918.         qpic_t  *p;
  2919.  
  2920.         if (!slist_sorted)
  2921.         {
  2922.                 if (hostCacheCount > 1)
  2923.                 {
  2924.                         int     i,j;
  2925.                         hostcache_t temp;
  2926.                         for (i = 0; i < hostCacheCount; i++)
  2927.                                 for (j = i+1; j < hostCacheCount; j++)
  2928.                                         if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
  2929.                                         {
  2930.                                                 Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
  2931.                                                 Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
  2932.                                                 Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
  2933.                                         }
  2934.                 }
  2935.                 slist_sorted = true;
  2936.         }
  2937.  
  2938.         p = Draw_CachePic ("gfx/p_multi.lmp");
  2939.         M_DrawPic ( (320-p->width)/2, 4, p);
  2940.         for (n = 0; n < hostCacheCount; n++)
  2941.         {
  2942.                 if (hostcache[n].maxusers)
  2943.                         sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
  2944.                 else
  2945.                         sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
  2946.                 M_Print (16, 32 + 8*n, string);
  2947.         }
  2948.         M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
  2949.  
  2950.         if (*m_return_reason)
  2951.                 M_PrintWhite (16, 148, m_return_reason);
  2952. }
  2953.  
  2954.  
  2955. void M_ServerList_Key (int k)
  2956. {
  2957.         switch (k)
  2958.         {
  2959.         case K_ESCAPE:
  2960.                 M_Menu_LanConfig_f ();
  2961.                 break;
  2962.  
  2963.         case K_SPACE:
  2964.                 M_Menu_Search_f ();
  2965.                 break;
  2966.  
  2967.         case K_UPARROW:
  2968.         case K_LEFTARROW:
  2969.                 S_LocalSound ("misc/menu1.wav");
  2970.                 slist_cursor--;
  2971.                 if (slist_cursor < 0)
  2972.                         slist_cursor = hostCacheCount - 1;
  2973.                 break;
  2974.  
  2975.         case K_DOWNARROW:
  2976.         case K_RIGHTARROW:
  2977.                 S_LocalSound ("misc/menu1.wav");
  2978.                 slist_cursor++;
  2979.                 if (slist_cursor >= hostCacheCount)
  2980.                         slist_cursor = 0;
  2981.                 break;
  2982.  
  2983.         case K_ENTER:
  2984.                 S_LocalSound ("misc/menu2.wav");
  2985.                 m_return_state = m_state;
  2986.                 m_return_onerror = true;
  2987.                 slist_sorted = false;
  2988.                 key_dest = key_game;
  2989.                 m_state = m_none;
  2990.                 Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
  2991.                 break;
  2992.  
  2993.         default:
  2994.                 break;
  2995.         }
  2996.  
  2997. }
  2998.  
  2999. //=============================================================================
  3000. /* Menu Subsystem */
  3001.  
  3002.  
  3003. void M_Init (void)
  3004. {
  3005.         Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
  3006.  
  3007.         Cmd_AddCommand ("menu_main", M_Menu_Main_f);
  3008.         Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
  3009.         Cmd_AddCommand ("menu_load", M_Menu_Load_f);
  3010.         Cmd_AddCommand ("menu_save", M_Menu_Save_f);
  3011.         Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
  3012.         Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
  3013.         Cmd_AddCommand ("menu_options", M_Menu_Options_f);
  3014.         Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
  3015.         Cmd_AddCommand ("menu_video", M_Menu_Video_f);
  3016.         Cmd_AddCommand ("help", M_Menu_Help_f);
  3017.         Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
  3018. }
  3019.  
  3020.  
  3021. void M_Draw (void)
  3022. {
  3023.         if (m_state == m_none || key_dest != key_menu)
  3024.                 return;
  3025.  
  3026.         if (!m_recursiveDraw)
  3027.         {
  3028.                 scr_copyeverything = 1;
  3029.  
  3030.                 if (scr_con_current)
  3031.                 {
  3032.                         Draw_ConsoleBackground (vid.height);
  3033.                         VID_UnlockBuffer ();
  3034.                         S_ExtraUpdate ();
  3035.                         VID_LockBuffer ();
  3036.                 }
  3037.                 else
  3038.                         Draw_FadeScreen ();
  3039.  
  3040.                 scr_fullupdate = 0;
  3041.         }
  3042.         else
  3043.         {
  3044.                 m_recursiveDraw = false;
  3045.         }
  3046.  
  3047.         switch (m_state)
  3048.         {
  3049.         case m_none:
  3050.                 break;
  3051.  
  3052.         case m_main:
  3053.                 M_Main_Draw ();
  3054.                 break;
  3055.  
  3056.         case m_singleplayer:
  3057.                 M_SinglePlayer_Draw ();
  3058.                 break;
  3059.  
  3060.         case m_load:
  3061.                 M_Load_Draw ();
  3062.                 break;
  3063.  
  3064.         case m_save:
  3065.                 M_Save_Draw ();
  3066.                 break;
  3067.  
  3068.         case m_multiplayer:
  3069.                 M_MultiPlayer_Draw ();
  3070.                 break;
  3071.  
  3072.         case m_setup:
  3073.                 M_Setup_Draw ();
  3074.                 break;
  3075.  
  3076.         case m_net:
  3077.                 M_Net_Draw ();
  3078.                 break;
  3079.  
  3080.         case m_options:
  3081.                 M_Options_Draw ();
  3082.                 break;
  3083.  
  3084.         case m_keys:
  3085.                 M_Keys_Draw ();
  3086.                 break;
  3087.  
  3088.         case m_video:
  3089.                 M_Video_Draw ();
  3090.                 break;
  3091.  
  3092.         case m_help:
  3093.                 M_Help_Draw ();
  3094.                 break;
  3095.  
  3096.         case m_quit:
  3097.                 M_Quit_Draw ();
  3098.                 break;
  3099.  
  3100.         case m_serialconfig:
  3101.                 M_SerialConfig_Draw ();
  3102.                 break;
  3103.  
  3104.         case m_modemconfig:
  3105.                 M_ModemConfig_Draw ();
  3106.                 break;
  3107.  
  3108.         case m_lanconfig:
  3109.                 M_LanConfig_Draw ();
  3110.                 break;
  3111.  
  3112.         case m_gameoptions:
  3113.                 M_GameOptions_Draw ();
  3114.                 break;
  3115.  
  3116.         case m_search:
  3117.                 M_Search_Draw ();
  3118.                 break;
  3119.  
  3120.         case m_slist:
  3121.                 M_ServerList_Draw ();
  3122.                 break;
  3123.         }
  3124.  
  3125.         if (m_entersound)
  3126.         {
  3127.                 S_LocalSound ("misc/menu2.wav");
  3128.                 m_entersound = false;
  3129.         }
  3130.  
  3131.         VID_UnlockBuffer ();
  3132.         S_ExtraUpdate ();
  3133.         VID_LockBuffer ();
  3134. }
  3135.  
  3136.  
  3137. void M_Keydown (int key)
  3138. {
  3139.         switch (m_state)
  3140.         {
  3141.         case m_none:
  3142.                 return;
  3143.  
  3144.         case m_main:
  3145.                 M_Main_Key (key);
  3146.                 return;
  3147.  
  3148.         case m_singleplayer:
  3149.                 M_SinglePlayer_Key (key);
  3150.                 return;
  3151.  
  3152.         case m_load:
  3153.                 M_Load_Key (key);
  3154.                 return;
  3155.  
  3156.         case m_save:
  3157.                 M_Save_Key (key);
  3158.                 return;
  3159.  
  3160.         case m_multiplayer:
  3161.                 M_MultiPlayer_Key (key);
  3162.                 return;
  3163.  
  3164.         case m_setup:
  3165.                 M_Setup_Key (key);
  3166.                 return;
  3167.  
  3168.         case m_net:
  3169.                 M_Net_Key (key);
  3170.                 return;
  3171.  
  3172.         case m_options:
  3173.                 M_Options_Key (key);
  3174.                 return;
  3175.  
  3176.         case m_keys:
  3177.                 M_Keys_Key (key);
  3178.                 return;
  3179.  
  3180.         case m_video:
  3181.                 M_Video_Key (key);
  3182.                 return;
  3183.  
  3184.         case m_help:
  3185.                 M_Help_Key (key);
  3186.                 return;
  3187.  
  3188.         case m_quit:
  3189.                 M_Quit_Key (key);
  3190.                 return;
  3191.  
  3192.         case m_serialconfig:
  3193.                 M_SerialConfig_Key (key);
  3194.                 return;
  3195.  
  3196.         case m_modemconfig:
  3197.                 M_ModemConfig_Key (key);
  3198.                 return;
  3199.  
  3200.         case m_lanconfig:
  3201.                 M_LanConfig_Key (key);
  3202.                 return;
  3203.  
  3204.         case m_gameoptions:
  3205.                 M_GameOptions_Key (key);
  3206.                 return;
  3207.  
  3208.         case m_search:
  3209.                 M_Search_Key (key);
  3210.                 break;
  3211.  
  3212.         case m_slist:
  3213.                 M_ServerList_Key (key);
  3214.                 return;
  3215.         }
  3216. }
  3217.  
  3218.  
  3219. void M_ConfigureNetSubsystem(void)
  3220. {
  3221. // enable/disable net systems to match desired config
  3222.  
  3223.         Cbuf_AddText ("stopdemo\n");
  3224.         if (SerialConfig || DirectConfig)
  3225.         {
  3226.                 Cbuf_AddText ("com1 enable\n");
  3227.         }
  3228.  
  3229.         if (IPXConfig || TCPIPConfig)
  3230.                 net_hostport = lanConfig_port;
  3231. }
  3232.