1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
26void (*vid_menudrawfn)(void);
27void (*vid_menukeyfn)(int key);
28
29enum m_state_t {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
31void 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);
43void M_Menu_SerialConfig_f (void);
44  void M_Menu_ModemConfig_f (void);
45void M_Menu_LanConfig_f (void);
46void M_Menu_GameOptions_f (void);
47void M_Menu_Search_f (void);
48void M_Menu_ServerList_f (void);
49
50void 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);
62void M_SerialConfig_Draw (void);
63  void M_ModemConfig_Draw (void);
64void M_LanConfig_Draw (void);
65void M_GameOptions_Draw (void);
66void M_Search_Draw (void);
67void M_ServerList_Draw (void);
68
69void 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);
81void M_SerialConfig_Key (int key);
82  void M_ModemConfig_Key (int key);
83void M_LanConfig_Key (int key);
84void M_GameOptions_Key (int key);
85void M_Search_Key (int key);
86void M_ServerList_Key (int key);
87
88qboolean    m_entersound;        // play after drawing a frame, so caching
89                // won't disrupt the sound
90qboolean    m_recursiveDraw;
91
92int            m_return_state;
93qboolean    m_return_onerror;
94char        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
103void M_ConfigureNetSubsystem(void);
104
105/*
106================
107M_DrawCharacter
108
109Draws one solid graphics character
110================
111*/
112void M_DrawCharacter (int cx, int line, int num)
113{
114  Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
115}
116
117void M_Print (int cx, int cy, const char *str)
118{
119  while (*str)
120  {
121    M_DrawCharacter (cx, cy, (*str)+128);
122    str++;
123    cx += 8;
124  }
125}
126
127void M_PrintWhite (int cx, int cy, const char *str)
128{
129  while (*str)
130  {
131    M_DrawCharacter (cx, cy, *str);
132    str++;
133    cx += 8;
134  }
135}
136
137void M_DrawTransPic (int x, int y, qpic_t *pic)
138{
139  Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
140}
141
142void M_DrawPic (int x, int y, qpic_t *pic)
143{
144  Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
145}
146
147byte identityTable[256];
148byte translationTable[256];
149
150void 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
175void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
176{
177  Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
178}
179
180
181void 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
238int m_save_demonum;
239
240/*
241================
242M_ToggleMenu_f
243================
244*/
245void 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
274int    m_main_cursor;
275#define    MAIN_ITEMS    5
276
277
278void 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
291void 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
307void 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
362int    m_singleplayer_cursor;
363#define    SINGLEPLAYER_ITEMS    3
364
365
366void M_Menu_SinglePlayer_f (void)
367{
368  key_dest = key_menu;
369  m_state = m_singleplayer;
370  m_entersound = true;
371}
372
373
374void 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
390void 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
440int        load_cursor;        // 0 < load_cursor < MAX_SAVEGAMES
441
442#define    MAX_SAVEGAMES        12
443char    m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
444int        loadable[MAX_SAVEGAMES];
445
446void 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
474void 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
483void 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
498void 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
514void 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
530void 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
572void 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
607int    m_multiplayer_cursor;
608#define    MULTIPLAYER_ITEMS    3
609
610
611void M_Menu_MultiPlayer_f (void)
612{
613  key_dest = key_menu;
614  m_state = m_multiplayer;
615  m_entersound = true;
616}
617
618
619void 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
639void 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
683int        setup_cursor = 4;
684int        setup_cursor_table[] = {40, 56, 80, 104, 140};
685
686char    setup_hostname[16];
687char    setup_myname[16];
688int        setup_oldtop;
689int        setup_oldbottom;
690int        setup_top;
691int        setup_bottom;
692
693#define    NUM_SETUP_CMDS    5
694
695void 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
707void 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
745void 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;
781forward:
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
857int    m_net_cursor;
858int m_net_items;
859int m_net_saveHeight;
860
861const 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
885void 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
899void 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
978void M_Net_Key (int k)
979{
980again:
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
1047int        options_cursor;
1048
1049void 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
1064void 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
1149void 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 ((int) (x + (SLIDER_RANGE-1)*8 * range), y, 131);
1162}
1163
1164void 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
1178void 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, (int) lookspring.value);
1219
1220  M_Print (16, 120, "            Lookstrafe");
1221  M_DrawCheckbox (220, 120, (int) 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
1239void 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
1315const 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
1339int        keys_cursor;
1340int        bind_grab;
1341
1342void M_Menu_Keys_f (void)
1343{
1344  key_dest = key_menu;
1345  m_state = m_keys;
1346  m_entersound = true;
1347}
1348
1349
1350void M_FindKeysForCommand (const 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
1376void M_UnbindCommand (const 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
1395void M_Keys_Draw (void)
1396{
1397  int        i, l;
1398  int        keys[2];
1399  const 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< (int) (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
1446void 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 >= (int)(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
1509void M_Menu_Video_f (void)
1510{
1511  key_dest = key_menu;
1512  m_state = m_video;
1513  m_entersound = true;
1514}
1515
1516
1517void M_Video_Draw (void)
1518{
1519  (*vid_menudrawfn) ();
1520}
1521
1522
1523void M_Video_Key (int key)
1524{
1525  (*vid_menukeyfn) (key);
1526}
1527
1528//=============================================================================
1529/* HELP MENU */
1530
1531int        help_page;
1532#define    NUM_HELP_PAGES    6
1533
1534
1535void M_Menu_Help_f (void)
1536{
1537#if 1 // Hijack menu for timedemo
1538      key_dest = key_menu;
1539      m_state = m_none;
1540      char buf[50];
1541      strcpy(buf, "timedemo demo1");
1542      Cmd_TokenizeString(buf);
1543      CL_TimeDemo_f();
1544#else
1545  key_dest = key_menu;
1546  m_state = m_help;
1547  m_entersound = true;
1548  help_page = 0;
1549#endif
1550}
1551
1552
1553
1554void M_Help_Draw (void)
1555{
1556  M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
1557}
1558
1559
1560void M_Help_Key (int key)
1561{
1562  switch (key)
1563  {
1564  case K_ESCAPE:
1565    M_Menu_Main_f ();
1566    break;
1567
1568  case K_UPARROW:
1569  case K_RIGHTARROW:
1570    m_entersound = true;
1571    if (++help_page >= NUM_HELP_PAGES)
1572      help_page = 0;
1573    break;
1574
1575  case K_DOWNARROW:
1576  case K_LEFTARROW:
1577    m_entersound = true;
1578    if (--help_page < 0)
1579      help_page = NUM_HELP_PAGES-1;
1580    break;
1581  }
1582
1583}
1584
1585//=============================================================================
1586/* QUIT MENU */
1587
1588int        msgNumber;
1589int        m_quit_prevstate;
1590qboolean    wasInMenus;
1591
1592#ifndef    _WIN32
1593const char *quitMessage [] =
1594{
1595/* .........1.........2.... */
1596  "  Are you gonna quit    ",
1597  "  this game just like   ",
1598  "   everything else?     ",
1599  "                        ",
1600
1601  " Milord, methinks that  ",
1602  "   thou art a lowly     ",
1603  " quitter. Is this true? ",
1604  "                        ",
1605
1606  " Do I need to bust your ",
1607  "  face open for trying  ",
1608  "        to quit?        ",
1609  "                        ",
1610
1611  " Man, I oughta smack you",
1612  "   for trying to quit!  ",
1613  "     Press Y to get     ",
1614  "      smacked out.      ",
1615
1616  " Press Y to quit like a ",
1617  "   big loser in life.   ",
1618  "  Press N to stay proud ",
1619  "    and successful!     ",
1620
1621  "   If you press Y to    ",
1622  "  quit, I will summon   ",
1623  "  Satan all over your   ",
1624  "      hard drive!       ",
1625
1626  "  Um, Asmodeus dislikes ",
1627  " his children trying to ",
1628  " quit. Press Y to return",
1629  "   to your Tinkertoys.  ",
1630
1631  "  If you quit now, I'll ",
1632  "  throw a blanket-party ",
1633  "   for you next time!   ",
1634  "                        "
1635};
1636#endif
1637
1638void M_Menu_Quit_f (void)
1639{
1640  if (m_state == m_quit)
1641    return;
1642  wasInMenus = (key_dest == key_menu);
1643  key_dest = key_menu;
1644  m_quit_prevstate = m_state;
1645  m_state = m_quit;
1646  m_entersound = true;
1647  msgNumber = rand()&7;
1648}
1649
1650
1651void M_Quit_Key (int key)
1652{
1653  switch (key)
1654  {
1655  case K_ESCAPE:
1656  case 'n':
1657  case 'N':
1658    if (wasInMenus)
1659    {
1660      m_state = (m_state_t) m_quit_prevstate;
1661      m_entersound = true;
1662    }
1663    else
1664    {
1665      key_dest = key_game;
1666      m_state = (m_state_t) m_none;
1667    }
1668    break;
1669
1670  case 'Y':
1671  case 'y':
1672  case K_ENTER:
1673    key_dest = key_console;
1674    Host_Quit_f ();
1675    break;
1676
1677  default:
1678    break;
1679  }
1680
1681}
1682
1683
1684void M_Quit_Draw (void)
1685{
1686  if (wasInMenus)
1687  {
1688    m_state = (m_state_t) m_quit_prevstate;
1689    m_recursiveDraw = true;
1690    M_Draw ();
1691    m_state = m_quit;
1692  }
1693
1694#ifdef _WIN32
1695  M_DrawTextBox (0, 0, 38, 23);
1696  M_PrintWhite (16, 12,  "  Quake version 1.09 by id Software\n\n");
1697  M_PrintWhite (16, 28,  "Programming        Art \n");
1698  M_Print (16, 36,  " John Carmack       Adrian Carmack\n");
1699  M_Print (16, 44,  " Michael Abrash     Kevin Cloud\n");
1700  M_Print (16, 52,  " John Cash          Paul Steed\n");
1701  M_Print (16, 60,  " Dave 'Zoid' Kirsch\n");
1702  M_PrintWhite (16, 68,  "Design             Biz\n");
1703  M_Print (16, 76,  " John Romero        Jay Wilbur\n");
1704  M_Print (16, 84,  " Sandy Petersen     Mike Wilson\n");
1705  M_Print (16, 92,  " American McGee     Donna Jackson\n");
1706  M_Print (16, 100,  " Tim Willits        Todd Hollenshead\n");
1707  M_PrintWhite (16, 108, "Support            Projects\n");
1708  M_Print (16, 116, " Barrett Alexander  Shawn Green\n");
1709  M_PrintWhite (16, 124, "Sound Effects\n");
1710  M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
1711  M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
1712  M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
1713  M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
1714  M_PrintWhite (16, 164, "registered trademark licensed to\n");
1715  M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
1716  M_PrintWhite (16, 180, "reserved. Press y to exit\n");
1717#else
1718  M_DrawTextBox (56, 76, 24, 4);
1719#if 0
1720  M_Print (64, 84,  quitMessage[msgNumber*4+0]);
1721  M_Print (64, 92,  quitMessage[msgNumber*4+1]);
1722  M_Print (64, 100, quitMessage[msgNumber*4+2]);
1723  M_Print (64, 108, quitMessage[msgNumber*4+3]);
1724#else
1725  M_PrintWhite(64, 92, "Click Trackball to Quit");
1726#endif
1727#endif
1728}
1729
1730//=============================================================================
1731
1732/* SERIAL CONFIG MENU */
1733
1734int        serialConfig_cursor;
1735int        serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
1736#define    NUM_SERIALCONFIG_CMDS    6
1737
1738static int ISA_uarts[]    = {0x3f8,0x2f8,0x3e8,0x2e8};
1739static int ISA_IRQs[]    = {4,3,4,3};
1740int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
1741
1742int        serialConfig_comport;
1743int        serialConfig_irq ;
1744int        serialConfig_baud;
1745char    serialConfig_phone[16];
1746
1747void M_Menu_SerialConfig_f (void)
1748{
1749  int        n;
1750  int        port;
1751  int        baudrate;
1752  qboolean    useModem;
1753
1754  key_dest = key_menu;
1755  m_state = m_serialconfig;
1756  m_entersound = true;
1757  if (JoiningGame && SerialConfig)
1758    serialConfig_cursor = 4;
1759  else
1760    serialConfig_cursor = 5;
1761
1762  (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
1763
1764  // map uart's port to COMx
1765  for (n = 0; n < 4; n++)
1766    if (ISA_uarts[n] == port)
1767      break;
1768  if (n == 4)
1769  {
1770    n = 0;
1771    serialConfig_irq = 4;
1772  }
1773  serialConfig_comport = n + 1;
1774
1775  // map baudrate to index
1776  for (n = 0; n < 6; n++)
1777    if (serialConfig_baudrate[n] == baudrate)
1778      break;
1779  if (n == 6)
1780    n = 5;
1781  serialConfig_baud = n;
1782
1783  m_return_onerror = false;
1784  m_return_reason[0] = 0;
1785}
1786
1787
1788void M_SerialConfig_Draw (void)
1789{
1790  qpic_t    *p;
1791  int        basex;
1792  const char    *startJoin;
1793  const char    *directModem;
1794
1795  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1796  p = Draw_CachePic ("gfx/p_multi.lmp");
1797  basex = (320-p->width)/2;
1798  M_DrawPic (basex, 4, p);
1799
1800  if (StartingGame)
1801    startJoin = "New Game";
1802  else
1803    startJoin = "Join Game";
1804  if (SerialConfig)
1805    directModem = "Modem";
1806  else
1807    directModem = "Direct Connect";
1808  M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
1809  basex += 8;
1810
1811  M_Print (basex, serialConfig_cursor_table[0], "Port");
1812  M_DrawTextBox (160, 40, 4, 1);
1813  M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
1814
1815  M_Print (basex, serialConfig_cursor_table[1], "IRQ");
1816  M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
1817  M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
1818
1819  M_Print (basex, serialConfig_cursor_table[2], "Baud");
1820  M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
1821  M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
1822
1823  if (SerialConfig)
1824  {
1825    M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
1826    if (JoiningGame)
1827    {
1828      M_Print (basex, serialConfig_cursor_table[4], "Phone number");
1829      M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
1830      M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
1831    }
1832  }
1833
1834  if (JoiningGame)
1835  {
1836    M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
1837    M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
1838  }
1839  else
1840  {
1841    M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
1842    M_Print (basex+8, serialConfig_cursor_table[5], "OK");
1843  }
1844
1845  M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
1846
1847  if (serialConfig_cursor == 4)
1848    M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
1849
1850  if (*m_return_reason)
1851    M_PrintWhite (basex, 148, m_return_reason);
1852}
1853
1854
1855void M_SerialConfig_Key (int key)
1856{
1857  int        l;
1858
1859  switch (key)
1860  {
1861  case K_ESCAPE:
1862    M_Menu_Net_f ();
1863    break;
1864
1865  case K_UPARROW:
1866    S_LocalSound ("misc/menu1.wav");
1867    serialConfig_cursor--;
1868    if (serialConfig_cursor < 0)
1869      serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
1870    break;
1871
1872  case K_DOWNARROW:
1873    S_LocalSound ("misc/menu1.wav");
1874    serialConfig_cursor++;
1875    if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
1876      serialConfig_cursor = 0;
1877    break;
1878
1879  case K_LEFTARROW:
1880    if (serialConfig_cursor > 2)
1881      break;
1882    S_LocalSound ("misc/menu3.wav");
1883
1884    if (serialConfig_cursor == 0)
1885    {
1886      serialConfig_comport--;
1887      if (serialConfig_comport == 0)
1888        serialConfig_comport = 4;
1889      serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1890    }
1891
1892    if (serialConfig_cursor == 1)
1893    {
1894      serialConfig_irq--;
1895      if (serialConfig_irq == 6)
1896        serialConfig_irq = 5;
1897      if (serialConfig_irq == 1)
1898        serialConfig_irq = 7;
1899    }
1900
1901    if (serialConfig_cursor == 2)
1902    {
1903      serialConfig_baud--;
1904      if (serialConfig_baud < 0)
1905        serialConfig_baud = 5;
1906    }
1907
1908    break;
1909
1910  case K_RIGHTARROW:
1911    if (serialConfig_cursor > 2)
1912      break;
1913forward:
1914    S_LocalSound ("misc/menu3.wav");
1915
1916    if (serialConfig_cursor == 0)
1917    {
1918      serialConfig_comport++;
1919      if (serialConfig_comport > 4)
1920        serialConfig_comport = 1;
1921      serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1922    }
1923
1924    if (serialConfig_cursor == 1)
1925    {
1926      serialConfig_irq++;
1927      if (serialConfig_irq == 6)
1928        serialConfig_irq = 7;
1929      if (serialConfig_irq == 8)
1930        serialConfig_irq = 2;
1931    }
1932
1933    if (serialConfig_cursor == 2)
1934    {
1935      serialConfig_baud++;
1936      if (serialConfig_baud > 5)
1937        serialConfig_baud = 0;
1938    }
1939
1940    break;
1941
1942  case K_ENTER:
1943    if (serialConfig_cursor < 3)
1944      goto forward;
1945
1946    m_entersound = true;
1947
1948    if (serialConfig_cursor == 3)
1949    {
1950      (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1951
1952      M_Menu_ModemConfig_f ();
1953      break;
1954    }
1955
1956    if (serialConfig_cursor == 4)
1957    {
1958      serialConfig_cursor = 5;
1959      break;
1960    }
1961
1962    // serialConfig_cursor == 5 (OK/CONNECT)
1963    (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1964
1965    M_ConfigureNetSubsystem ();
1966
1967    if (StartingGame)
1968    {
1969      M_Menu_GameOptions_f ();
1970      break;
1971    }
1972
1973    m_return_state = m_state;
1974    m_return_onerror = true;
1975    key_dest = key_game;
1976    m_state = m_none;
1977
1978    if (SerialConfig)
1979      Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
1980    else
1981      Cbuf_AddText ("connect\n");
1982    break;
1983
1984  case K_BACKSPACE:
1985    if (serialConfig_cursor == 4)
1986    {
1987      if (strlen(serialConfig_phone))
1988        serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
1989    }
1990    break;
1991
1992  default:
1993    if (key < 32 || key > 127)
1994      break;
1995    if (serialConfig_cursor == 4)
1996    {
1997      l = strlen(serialConfig_phone);
1998      if (l < 15)
1999      {
2000        serialConfig_phone[l+1] = 0;
2001        serialConfig_phone[l] = key;
2002      }
2003    }
2004  }
2005
2006  if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
2007  {
2008    if (key == K_UPARROW)
2009      serialConfig_cursor = 2;
2010    else
2011      serialConfig_cursor = 5;
2012  }
2013  if (SerialConfig && StartingGame && serialConfig_cursor == 4)
2014  {
2015    if (key == K_UPARROW)
2016      serialConfig_cursor = 3;
2017    else
2018      serialConfig_cursor = 5;
2019  }
2020}
2021
2022//=============================================================================
2023/* MODEM CONFIG MENU */
2024
2025int        modemConfig_cursor;
2026int        modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
2027#define NUM_MODEMCONFIG_CMDS    5
2028
2029char    modemConfig_dialing;
2030char    modemConfig_clear [16];
2031char    modemConfig_init [32];
2032char    modemConfig_hangup [16];
2033
2034void M_Menu_ModemConfig_f (void)
2035{
2036  key_dest = key_menu;
2037  m_state = m_modemconfig;
2038  m_entersound = true;
2039  (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
2040}
2041
2042
2043void M_ModemConfig_Draw (void)
2044{
2045  qpic_t    *p;
2046  int        basex;
2047
2048  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2049  p = Draw_CachePic ("gfx/p_multi.lmp");
2050  basex = (320-p->width)/2;
2051  M_DrawPic (basex, 4, p);
2052  basex += 8;
2053
2054  if (modemConfig_dialing == 'P')
2055    M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
2056  else
2057    M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
2058
2059  M_Print (basex, modemConfig_cursor_table[1], "Clear");
2060  M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
2061  M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
2062  if (modemConfig_cursor == 1)
2063    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
2064
2065  M_Print (basex, modemConfig_cursor_table[2], "Init");
2066  M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
2067  M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
2068  if (modemConfig_cursor == 2)
2069    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
2070
2071  M_Print (basex, modemConfig_cursor_table[3], "Hangup");
2072  M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
2073  M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
2074  if (modemConfig_cursor == 3)
2075    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
2076
2077  M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
2078  M_Print (basex+8, modemConfig_cursor_table[4], "OK");
2079
2080  M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
2081}
2082
2083
2084void M_ModemConfig_Key (int key)
2085{
2086  int        l;
2087
2088  switch (key)
2089  {
2090  case K_ESCAPE:
2091    M_Menu_SerialConfig_f ();
2092    break;
2093
2094  case K_UPARROW:
2095    S_LocalSound ("misc/menu1.wav");
2096    modemConfig_cursor--;
2097    if (modemConfig_cursor < 0)
2098      modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
2099    break;
2100
2101  case K_DOWNARROW:
2102    S_LocalSound ("misc/menu1.wav");
2103    modemConfig_cursor++;
2104    if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
2105      modemConfig_cursor = 0;
2106    break;
2107
2108  case K_LEFTARROW:
2109  case K_RIGHTARROW:
2110    if (modemConfig_cursor == 0)
2111    {
2112      if (modemConfig_dialing == 'P')
2113        modemConfig_dialing = 'T';
2114      else
2115        modemConfig_dialing = 'P';
2116      S_LocalSound ("misc/menu1.wav");
2117    }
2118    break;
2119
2120  case K_ENTER:
2121    if (modemConfig_cursor == 0)
2122    {
2123      if (modemConfig_dialing == 'P')
2124        modemConfig_dialing = 'T';
2125      else
2126        modemConfig_dialing = 'P';
2127      m_entersound = true;
2128    }
2129
2130    if (modemConfig_cursor == 4)
2131    {
2132      (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
2133      m_entersound = true;
2134      M_Menu_SerialConfig_f ();
2135    }
2136    break;
2137
2138  case K_BACKSPACE:
2139    if (modemConfig_cursor == 1)
2140    {
2141      if (strlen(modemConfig_clear))
2142        modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
2143    }
2144
2145    if (modemConfig_cursor == 2)
2146    {
2147      if (strlen(modemConfig_init))
2148        modemConfig_init[strlen(modemConfig_init)-1] = 0;
2149    }
2150
2151    if (modemConfig_cursor == 3)
2152    {
2153      if (strlen(modemConfig_hangup))
2154        modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
2155    }
2156    break;
2157
2158  default:
2159    if (key < 32 || key > 127)
2160      break;
2161
2162    if (modemConfig_cursor == 1)
2163    {
2164      l = strlen(modemConfig_clear);
2165      if (l < 15)
2166      {
2167        modemConfig_clear[l+1] = 0;
2168        modemConfig_clear[l] = key;
2169      }
2170    }
2171
2172    if (modemConfig_cursor == 2)
2173    {
2174      l = strlen(modemConfig_init);
2175      if (l < 29)
2176      {
2177        modemConfig_init[l+1] = 0;
2178        modemConfig_init[l] = key;
2179      }
2180    }
2181
2182    if (modemConfig_cursor == 3)
2183    {
2184      l = strlen(modemConfig_hangup);
2185      if (l < 15)
2186      {
2187        modemConfig_hangup[l+1] = 0;
2188        modemConfig_hangup[l] = key;
2189      }
2190    }
2191  }
2192}
2193
2194//=============================================================================
2195/* LAN CONFIG MENU */
2196
2197int        lanConfig_cursor = -1;
2198int        lanConfig_cursor_table [] = {72, 92, 124};
2199#define NUM_LANCONFIG_CMDS    3
2200
2201int     lanConfig_port;
2202char    lanConfig_portname[6];
2203char    lanConfig_joinname[22];
2204
2205void M_Menu_LanConfig_f (void)
2206{
2207  key_dest = key_menu;
2208  m_state = m_lanconfig;
2209  m_entersound = true;
2210  if (lanConfig_cursor == -1)
2211  {
2212    if (JoiningGame && TCPIPConfig)
2213      lanConfig_cursor = 2;
2214    else
2215      lanConfig_cursor = 1;
2216  }
2217  if (StartingGame && lanConfig_cursor == 2)
2218    lanConfig_cursor = 1;
2219  lanConfig_port = DEFAULTnet_hostport;
2220  sprintf(lanConfig_portname, "%u", lanConfig_port);
2221
2222  m_return_onerror = false;
2223  m_return_reason[0] = 0;
2224}
2225
2226
2227void M_LanConfig_Draw (void)
2228{
2229  qpic_t    *p;
2230  int        basex;
2231  const char    *startJoin;
2232  const char    *protocol;
2233
2234  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2235  p = Draw_CachePic ("gfx/p_multi.lmp");
2236  basex = (320-p->width)/2;
2237  M_DrawPic (basex, 4, p);
2238
2239  if (StartingGame)
2240    startJoin = "New Game";
2241  else
2242    startJoin = "Join Game";
2243  if (IPXConfig)
2244    protocol = "IPX";
2245  else
2246    protocol = "TCP/IP";
2247  M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
2248  basex += 8;
2249
2250  M_Print (basex, 52, "Address:");
2251  if (IPXConfig)
2252    M_Print (basex+9*8, 52, my_ipx_address);
2253  else
2254    M_Print (basex+9*8, 52, my_tcpip_address);
2255
2256  M_Print (basex, lanConfig_cursor_table[0], "Port");
2257  M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
2258  M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
2259
2260  if (JoiningGame)
2261  {
2262    M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
2263    M_Print (basex, 108, "Join game at:");
2264    M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
2265    M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
2266  }
2267  else
2268  {
2269    M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
2270    M_Print (basex+8, lanConfig_cursor_table[1], "OK");
2271  }
2272
2273  M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
2274
2275  if (lanConfig_cursor == 0)
2276    M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
2277
2278  if (lanConfig_cursor == 2)
2279    M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
2280
2281  if (*m_return_reason)
2282    M_PrintWhite (basex, 148, m_return_reason);
2283}
2284
2285
2286void M_LanConfig_Key (int key)
2287{
2288  int        l;
2289
2290  switch (key)
2291  {
2292  case K_ESCAPE:
2293    M_Menu_Net_f ();
2294    break;
2295
2296  case K_UPARROW:
2297    S_LocalSound ("misc/menu1.wav");
2298    lanConfig_cursor--;
2299    if (lanConfig_cursor < 0)
2300      lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
2301    break;
2302
2303  case K_DOWNARROW:
2304    S_LocalSound ("misc/menu1.wav");
2305    lanConfig_cursor++;
2306    if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
2307      lanConfig_cursor = 0;
2308    break;
2309
2310  case K_ENTER:
2311    if (lanConfig_cursor == 0)
2312      break;
2313
2314    m_entersound = true;
2315
2316    M_ConfigureNetSubsystem ();
2317
2318    if (lanConfig_cursor == 1)
2319    {
2320      if (StartingGame)
2321      {
2322        M_Menu_GameOptions_f ();
2323        break;
2324      }
2325      M_Menu_Search_f();
2326      break;
2327    }
2328
2329    if (lanConfig_cursor == 2)
2330    {
2331      m_return_state = m_state;
2332      m_return_onerror = true;
2333      key_dest = key_game;
2334      m_state = m_none;
2335      Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
2336      break;
2337    }
2338
2339    break;
2340
2341  case K_BACKSPACE:
2342    if (lanConfig_cursor == 0)
2343    {
2344      if (strlen(lanConfig_portname))
2345        lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
2346    }
2347
2348    if (lanConfig_cursor == 2)
2349    {
2350      if (strlen(lanConfig_joinname))
2351        lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
2352    }
2353    break;
2354
2355  default:
2356    if (key < 32 || key > 127)
2357      break;
2358
2359    if (lanConfig_cursor == 2)
2360    {
2361      l = strlen(lanConfig_joinname);
2362      if (l < 21)
2363      {
2364        lanConfig_joinname[l+1] = 0;
2365        lanConfig_joinname[l] = key;
2366      }
2367    }
2368
2369    if (key < '0' || key > '9')
2370      break;
2371    if (lanConfig_cursor == 0)
2372    {
2373      l = strlen(lanConfig_portname);
2374      if (l < 5)
2375      {
2376        lanConfig_portname[l+1] = 0;
2377        lanConfig_portname[l] = key;
2378      }
2379    }
2380  }
2381
2382  if (StartingGame && lanConfig_cursor == 2)
2383  {
2384    if (key == K_UPARROW)
2385      lanConfig_cursor = 1;
2386    else
2387      lanConfig_cursor = 0;
2388  }
2389
2390  l =  Q_atoi(lanConfig_portname);
2391  if (l > 65535)
2392    l = lanConfig_port;
2393  else
2394    lanConfig_port = l;
2395  sprintf(lanConfig_portname, "%u", lanConfig_port);
2396}
2397
2398//=============================================================================
2399/* GAME OPTIONS MENU */
2400
2401typedef struct
2402{
2403  const char    *name;
2404  const char    *description;
2405} level_t;
2406
2407level_t        levels[] =
2408{
2409  {"start", "Entrance"},    // 0
2410
2411  {"e1m1", "Slipgate Complex"},                // 1
2412  {"e1m2", "Castle of the Damned"},
2413  {"e1m3", "The Necropolis"},
2414  {"e1m4", "The Grisly Grotto"},
2415  {"e1m5", "Gloom Keep"},
2416  {"e1m6", "The Door To Chthon"},
2417  {"e1m7", "The House of Chthon"},
2418  {"e1m8", "Ziggurat Vertigo"},
2419
2420  {"e2m1", "The Installation"},                // 9
2421  {"e2m2", "Ogre Citadel"},
2422  {"e2m3", "Crypt of Decay"},
2423  {"e2m4", "The Ebon Fortress"},
2424  {"e2m5", "The Wizard's Manse"},
2425  {"e2m6", "The Dismal Oubliette"},
2426  {"e2m7", "Underearth"},
2427
2428  {"e3m1", "Termination Central"},            // 16
2429  {"e3m2", "The Vaults of Zin"},
2430  {"e3m3", "The Tomb of Terror"},
2431  {"e3m4", "Satan's Dark Delight"},
2432  {"e3m5", "Wind Tunnels"},
2433  {"e3m6", "Chambers of Torment"},
2434  {"e3m7", "The Haunted Halls"},
2435
2436  {"e4m1", "The Sewage System"},                // 23
2437  {"e4m2", "The Tower of Despair"},
2438  {"e4m3", "The Elder God Shrine"},
2439  {"e4m4", "The Palace of Hate"},
2440  {"e4m5", "Hell's Atrium"},
2441  {"e4m6", "The Pain Maze"},
2442  {"e4m7", "Azure Agony"},
2443  {"e4m8", "The Nameless City"},
2444
2445  {"end", "Shub-Niggurath's Pit"},            // 31
2446
2447  {"dm1", "Place of Two Deaths"},                // 32
2448  {"dm2", "Claustrophobopolis"},
2449  {"dm3", "The Abandoned Base"},
2450  {"dm4", "The Bad Place"},
2451  {"dm5", "The Cistern"},
2452  {"dm6", "The Dark Zone"}
2453};
2454
2455//MED 01/06/97 added hipnotic levels
2456level_t     hipnoticlevels[] =
2457{
2458   {"start", "Command HQ"},  // 0
2459
2460   {"hip1m1", "The Pumping Station"},          // 1
2461   {"hip1m2", "Storage Facility"},
2462   {"hip1m3", "The Lost Mine"},
2463   {"hip1m4", "Research Facility"},
2464   {"hip1m5", "Military Complex"},
2465
2466   {"hip2m1", "Ancient Realms"},          // 6
2467   {"hip2m2", "The Black Cathedral"},
2468   {"hip2m3", "The Catacombs"},
2469   {"hip2m4", "The Crypt"},
2470   {"hip2m5", "Mortum's Keep"},
2471   {"hip2m6", "The Gremlin's Domain"},
2472
2473   {"hip3m1", "Tur Torment"},       // 12
2474   {"hip3m2", "Pandemonium"},
2475   {"hip3m3", "Limbo"},
2476   {"hip3m4", "The Gauntlet"},
2477
2478   {"hipend", "Armagon's Lair"},       // 16
2479
2480   {"hipdm1", "The Edge of Oblivion"}           // 17
2481};
2482
2483//PGM 01/07/97 added rogue levels
2484//PGM 03/02/97 added dmatch level
2485level_t        roguelevels[] =
2486{
2487  {"start",    "Split Decision"},
2488  {"r1m1",    "Deviant's Domain"},
2489  {"r1m2",    "Dread Portal"},
2490  {"r1m3",    "Judgement Call"},
2491  {"r1m4",    "Cave of Death"},
2492  {"r1m5",    "Towers of Wrath"},
2493  {"r1m6",    "Temple of Pain"},
2494  {"r1m7",    "Tomb of the Overlord"},
2495  {"r2m1",    "Tempus Fugit"},
2496  {"r2m2",    "Elemental Fury I"},
2497  {"r2m3",    "Elemental Fury II"},
2498  {"r2m4",    "Curse of Osiris"},
2499  {"r2m5",    "Wizard's Keep"},
2500  {"r2m6",    "Blood Sacrifice"},
2501  {"r2m7",    "Last Bastion"},
2502  {"r2m8",    "Source of Evil"},
2503  {"ctf1",    "Division of Change"}
2504};
2505
2506typedef struct
2507{
2508  const char    *description;
2509  int        firstLevel;
2510  int        levels;
2511} episode_t;
2512
2513episode_t    episodes[] =
2514{
2515  {"Welcome to Quake", 0, 1},
2516  {"Doomed Dimension", 1, 8},
2517  {"Realm of Black Magic", 9, 7},
2518  {"Netherworld", 16, 7},
2519  {"The Elder World", 23, 8},
2520  {"Final Level", 31, 1},
2521  {"Deathmatch Arena", 32, 6}
2522};
2523
2524//MED 01/06/97  added hipnotic episodes
2525episode_t   hipnoticepisodes[] =
2526{
2527   {"Scourge of Armagon", 0, 1},
2528   {"Fortress of the Dead", 1, 5},
2529   {"Dominion of Darkness", 6, 6},
2530   {"The Rift", 12, 4},
2531   {"Final Level", 16, 1},
2532   {"Deathmatch Arena", 17, 1}
2533};
2534
2535//PGM 01/07/97 added rogue episodes
2536//PGM 03/02/97 added dmatch episode
2537episode_t    rogueepisodes[] =
2538{
2539  {"Introduction", 0, 1},
2540  {"Hell's Fortress", 1, 7},
2541  {"Corridors of Time", 8, 8},
2542  {"Deathmatch Arena", 16, 1}
2543};
2544
2545int    startepisode;
2546int    startlevel;
2547int maxplayers;
2548qboolean m_serverInfoMessage = false;
2549double m_serverInfoMessageTime;
2550
2551void M_Menu_GameOptions_f (void)
2552{
2553  key_dest = key_menu;
2554  m_state = m_gameoptions;
2555  m_entersound = true;
2556  if (maxplayers == 0)
2557    maxplayers = svs.maxclients;
2558  if (maxplayers < 2)
2559    maxplayers = svs.maxclientslimit;
2560}
2561
2562
2563int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
2564#define    NUM_GAMEOPTIONS    9
2565int        gameoptions_cursor;
2566
2567void M_GameOptions_Draw (void)
2568{
2569  qpic_t    *p;
2570  int        x;
2571
2572  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2573  p = Draw_CachePic ("gfx/p_multi.lmp");
2574  M_DrawPic ( (320-p->width)/2, 4, p);
2575
2576  M_DrawTextBox (152, 32, 10, 1);
2577  M_Print (160, 40, "begin game");
2578
2579  M_Print (0, 56, "      Max players");
2580  M_Print (160, 56, va("%i", maxplayers) );
2581
2582  M_Print (0, 64, "        Game Type");
2583  if (coop.value)
2584    M_Print (160, 64, "Cooperative");
2585  else
2586    M_Print (160, 64, "Deathmatch");
2587
2588  M_Print (0, 72, "        Teamplay");
2589  if (rogue)
2590  {
2591    const char *msg;
2592
2593    switch((int)teamplay.value)
2594    {
2595      case 1: msg = "No Friendly Fire"; break;
2596      case 2: msg = "Friendly Fire"; break;
2597      case 3: msg = "Tag"; break;
2598      case 4: msg = "Capture the Flag"; break;
2599      case 5: msg = "One Flag CTF"; break;
2600      case 6: msg = "Three Team CTF"; break;
2601      default: msg = "Off"; break;
2602    }
2603    M_Print (160, 72, msg);
2604  }
2605  else
2606  {
2607    const char *msg;
2608
2609    switch((int)teamplay.value)
2610    {
2611      case 1: msg = "No Friendly Fire"; break;
2612      case 2: msg = "Friendly Fire"; break;
2613      default: msg = "Off"; break;
2614    }
2615    M_Print (160, 72, msg);
2616  }
2617
2618  M_Print (0, 80, "            Skill");
2619  if (skill.value == 0)
2620    M_Print (160, 80, "Easy difficulty");
2621  else if (skill.value == 1)
2622    M_Print (160, 80, "Normal difficulty");
2623  else if (skill.value == 2)
2624    M_Print (160, 80, "Hard difficulty");
2625  else
2626    M_Print (160, 80, "Nightmare difficulty");
2627
2628  M_Print (0, 88, "       Frag Limit");
2629  if (fraglimit.value == 0)
2630    M_Print (160, 88, "none");
2631  else
2632    M_Print (160, 88, va("%i frags", (int)fraglimit.value));
2633
2634  M_Print (0, 96, "       Time Limit");
2635  if (timelimit.value == 0)
2636    M_Print (160, 96, "none");
2637  else
2638    M_Print (160, 96, va("%i minutes", (int)timelimit.value));
2639
2640  M_Print (0, 112, "         Episode");
2641   //MED 01/06/97 added hipnotic episodes
2642   if (hipnotic)
2643      M_Print (160, 112, hipnoticepisodes[startepisode].description);
2644   //PGM 01/07/97 added rogue episodes
2645   else if (rogue)
2646      M_Print (160, 112, rogueepisodes[startepisode].description);
2647   else
2648      M_Print (160, 112, episodes[startepisode].description);
2649
2650  M_Print (0, 120, "           Level");
2651   //MED 01/06/97 added hipnotic episodes
2652   if (hipnotic)
2653   {
2654      M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
2655      M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
2656   }
2657   //PGM 01/07/97 added rogue episodes
2658   else if (rogue)
2659   {
2660      M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
2661      M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
2662   }
2663   else
2664   {
2665      M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
2666      M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
2667   }
2668
2669// line cursor
2670  M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
2671
2672  if (m_serverInfoMessage)
2673  {
2674    if ((realtime - m_serverInfoMessageTime) < 5.0)
2675    {
2676      x = (320-26*8)/2;
2677      M_DrawTextBox (x, 138, 24, 4);
2678      x += 8;
2679      M_Print (x, 146, "  More than 4 players   ");
2680      M_Print (x, 154, " requires using command ");
2681      M_Print (x, 162, "line parameters; please ");
2682      M_Print (x, 170, "   see techinfo.txt.    ");
2683    }
2684    else
2685    {
2686      m_serverInfoMessage = false;
2687    }
2688  }
2689}
2690
2691
2692void M_NetStart_Change (int dir)
2693{
2694  int count;
2695
2696  switch (gameoptions_cursor)
2697  {
2698  case 1:
2699    maxplayers += dir;
2700    if (maxplayers > svs.maxclientslimit)
2701    {
2702      maxplayers = svs.maxclientslimit;
2703      m_serverInfoMessage = true;
2704      m_serverInfoMessageTime = realtime;
2705    }
2706    if (maxplayers < 2)
2707      maxplayers = 2;
2708    break;
2709
2710  case 2:
2711    Cvar_SetValue ("coop", coop.value ? 0 : 1);
2712    break;
2713
2714  case 3:
2715    if (rogue)
2716      count = 6;
2717    else
2718      count = 2;
2719
2720    Cvar_SetValue ("teamplay", teamplay.value + dir);
2721    if (teamplay.value > count)
2722      Cvar_SetValue ("teamplay", 0);
2723    else if (teamplay.value < 0)
2724      Cvar_SetValue ("teamplay", count);
2725    break;
2726
2727  case 4:
2728    Cvar_SetValue ("skill", skill.value + dir);
2729    if (skill.value > 3)
2730      Cvar_SetValue ("skill", 0);
2731    if (skill.value < 0)
2732      Cvar_SetValue ("skill", 3);
2733    break;
2734
2735  case 5:
2736    Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
2737    if (fraglimit.value > 100)
2738      Cvar_SetValue ("fraglimit", 0);
2739    if (fraglimit.value < 0)
2740      Cvar_SetValue ("fraglimit", 100);
2741    break;
2742
2743  case 6:
2744    Cvar_SetValue ("timelimit", timelimit.value + dir*5);
2745    if (timelimit.value > 60)
2746      Cvar_SetValue ("timelimit", 0);
2747    if (timelimit.value < 0)
2748      Cvar_SetValue ("timelimit", 60);
2749    break;
2750
2751  case 7:
2752    startepisode += dir;
2753  //MED 01/06/97 added hipnotic count
2754    if (hipnotic)
2755      count = 6;
2756  //PGM 01/07/97 added rogue count
2757  //PGM 03/02/97 added 1 for dmatch episode
2758    else if (rogue)
2759      count = 4;
2760    else if (registered.value)
2761      count = 7;
2762    else
2763      count = 2;
2764
2765    if (startepisode < 0)
2766      startepisode = count - 1;
2767
2768    if (startepisode >= count)
2769      startepisode = 0;
2770
2771    startlevel = 0;
2772    break;
2773
2774  case 8:
2775    startlevel += dir;
2776    //MED 01/06/97 added hipnotic episodes
2777    if (hipnotic)
2778      count = hipnoticepisodes[startepisode].levels;
2779  //PGM 01/06/97 added hipnotic episodes
2780    else if (rogue)
2781      count = rogueepisodes[startepisode].levels;
2782    else
2783      count = episodes[startepisode].levels;
2784
2785    if (startlevel < 0)
2786      startlevel = count - 1;
2787
2788    if (startlevel >= count)
2789      startlevel = 0;
2790    break;
2791  }
2792}
2793
2794void M_GameOptions_Key (int key)
2795{
2796  switch (key)
2797  {
2798  case K_ESCAPE:
2799    M_Menu_Net_f ();
2800    break;
2801
2802  case K_UPARROW:
2803    S_LocalSound ("misc/menu1.wav");
2804    gameoptions_cursor--;
2805    if (gameoptions_cursor < 0)
2806      gameoptions_cursor = NUM_GAMEOPTIONS-1;
2807    break;
2808
2809  case K_DOWNARROW:
2810    S_LocalSound ("misc/menu1.wav");
2811    gameoptions_cursor++;
2812    if (gameoptions_cursor >= NUM_GAMEOPTIONS)
2813      gameoptions_cursor = 0;
2814    break;
2815
2816  case K_LEFTARROW:
2817    if (gameoptions_cursor == 0)
2818      break;
2819    S_LocalSound ("misc/menu3.wav");
2820    M_NetStart_Change (-1);
2821    break;
2822
2823  case K_RIGHTARROW:
2824    if (gameoptions_cursor == 0)
2825      break;
2826    S_LocalSound ("misc/menu3.wav");
2827    M_NetStart_Change (1);
2828    break;
2829
2830  case K_ENTER:
2831    S_LocalSound ("misc/menu2.wav");
2832    if (gameoptions_cursor == 0)
2833    {
2834      if (sv.active)
2835        Cbuf_AddText ("disconnect\n");
2836      Cbuf_AddText ("listen 0\n");    // so host_netport will be re-examined
2837      Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
2838      SCR_BeginLoadingPlaque ();
2839
2840      if (hipnotic)
2841        Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
2842      else if (rogue)
2843        Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
2844      else
2845        Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
2846
2847      return;
2848    }
2849
2850    M_NetStart_Change (1);
2851    break;
2852  }
2853}
2854
2855//=============================================================================
2856/* SEARCH MENU */
2857
2858qboolean    searchComplete = false;
2859double        searchCompleteTime;
2860
2861void M_Menu_Search_f (void)
2862{
2863  key_dest = key_menu;
2864  m_state = m_search;
2865  m_entersound = false;
2866  slistSilent = true;
2867  slistLocal = false;
2868  searchComplete = false;
2869  NET_Slist_f();
2870
2871}
2872
2873
2874void M_Search_Draw (void)
2875{
2876  qpic_t    *p;
2877  int x;
2878
2879  p = Draw_CachePic ("gfx/p_multi.lmp");
2880  M_DrawPic ( (320-p->width)/2, 4, p);
2881  x = (320/2) - ((12*8)/2) + 4;
2882  M_DrawTextBox (x-8, 32, 12, 1);
2883  M_Print (x, 40, "Searching...");
2884
2885  if(slistInProgress)
2886  {
2887    NET_Poll();
2888    return;
2889  }
2890
2891  if (! searchComplete)
2892  {
2893    searchComplete = true;
2894    searchCompleteTime = realtime;
2895  }
2896
2897  if (hostCacheCount)
2898  {
2899    M_Menu_ServerList_f ();
2900    return;
2901  }
2902
2903  M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
2904  if ((realtime - searchCompleteTime) < 3.0)
2905    return;
2906
2907  M_Menu_LanConfig_f ();
2908}
2909
2910
2911void M_Search_Key (int key)
2912{
2913}
2914
2915//=============================================================================
2916/* SLIST MENU */
2917
2918int        slist_cursor;
2919qboolean slist_sorted;
2920
2921void M_Menu_ServerList_f (void)
2922{
2923  key_dest = key_menu;
2924  m_state = m_slist;
2925  m_entersound = true;
2926  slist_cursor = 0;
2927  m_return_onerror = false;
2928  m_return_reason[0] = 0;
2929  slist_sorted = false;
2930}
2931
2932
2933void M_ServerList_Draw (void)
2934{
2935  int        n;
2936  char    string [64];
2937  qpic_t    *p;
2938
2939  if (!slist_sorted)
2940  {
2941    if (hostCacheCount > 1)
2942    {
2943      int    i,j;
2944      hostcache_t temp;
2945      for (i = 0; i < hostCacheCount; i++)
2946        for (j = i+1; j < hostCacheCount; j++)
2947          if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
2948          {
2949            Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
2950            Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
2951            Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
2952          }
2953    }
2954    slist_sorted = true;
2955  }
2956
2957  p = Draw_CachePic ("gfx/p_multi.lmp");
2958  M_DrawPic ( (320-p->width)/2, 4, p);
2959  for (n = 0; n < hostCacheCount; n++)
2960  {
2961    if (hostcache[n].maxusers)
2962      sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
2963    else
2964      sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
2965    M_Print (16, 32 + 8*n, string);
2966  }
2967  M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
2968
2969  if (*m_return_reason)
2970    M_PrintWhite (16, 148, m_return_reason);
2971}
2972
2973
2974void M_ServerList_Key (int k)
2975{
2976  switch (k)
2977  {
2978  case K_ESCAPE:
2979    M_Menu_LanConfig_f ();
2980    break;
2981
2982  case K_SPACE:
2983    M_Menu_Search_f ();
2984    break;
2985
2986  case K_UPARROW:
2987  case K_LEFTARROW:
2988    S_LocalSound ("misc/menu1.wav");
2989    slist_cursor--;
2990    if (slist_cursor < 0)
2991      slist_cursor = hostCacheCount - 1;
2992    break;
2993
2994  case K_DOWNARROW:
2995  case K_RIGHTARROW:
2996    S_LocalSound ("misc/menu1.wav");
2997    slist_cursor++;
2998    if (slist_cursor >= hostCacheCount)
2999      slist_cursor = 0;
3000    break;
3001
3002  case K_ENTER:
3003    S_LocalSound ("misc/menu2.wav");
3004    m_return_state = m_state;
3005    m_return_onerror = true;
3006    slist_sorted = false;
3007    key_dest = key_game;
3008    m_state = m_none;
3009    Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
3010    break;
3011
3012  default:
3013    break;
3014  }
3015
3016}
3017
3018//=============================================================================
3019/* Menu Subsystem */
3020
3021
3022void M_Init (void)
3023{
3024  Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
3025
3026  Cmd_AddCommand ("menu_main", M_Menu_Main_f);
3027  Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
3028  Cmd_AddCommand ("menu_load", M_Menu_Load_f);
3029  Cmd_AddCommand ("menu_save", M_Menu_Save_f);
3030  Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
3031  Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
3032  Cmd_AddCommand ("menu_options", M_Menu_Options_f);
3033  Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
3034  Cmd_AddCommand ("menu_video", M_Menu_Video_f);
3035  Cmd_AddCommand ("help", M_Menu_Help_f);
3036  Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
3037}
3038
3039
3040void M_Draw (void)
3041{
3042  if (m_state == m_none || key_dest != key_menu)
3043    return;
3044
3045  if (!m_recursiveDraw)
3046  {
3047    scr_copyeverything = 1;
3048
3049    if (scr_con_current)
3050    {
3051      Draw_ConsoleBackground (vid.height);
3052      VID_UnlockBuffer ();
3053      S_ExtraUpdate ();
3054      VID_LockBuffer ();
3055    }
3056    else
3057      Draw_FadeScreen ();
3058
3059    scr_fullupdate = 0;
3060  }
3061  else
3062  {
3063    m_recursiveDraw = false;
3064  }
3065
3066  switch (m_state)
3067  {
3068  case m_none:
3069    break;
3070
3071  case m_main:
3072    M_Main_Draw ();
3073    break;
3074
3075  case m_singleplayer:
3076    M_SinglePlayer_Draw ();
3077    break;
3078
3079  case m_load:
3080    M_Load_Draw ();
3081    break;
3082
3083  case m_save:
3084    M_Save_Draw ();
3085    break;
3086
3087  case m_multiplayer:
3088    M_MultiPlayer_Draw ();
3089    break;
3090
3091  case m_setup:
3092    M_Setup_Draw ();
3093    break;
3094
3095  case m_net:
3096    M_Net_Draw ();
3097    break;
3098
3099  case m_options:
3100    M_Options_Draw ();
3101    break;
3102
3103  case m_keys:
3104    M_Keys_Draw ();
3105    break;
3106
3107  case m_video:
3108    M_Video_Draw ();
3109    break;
3110
3111  case m_help:
3112    M_Help_Draw ();
3113    break;
3114
3115  case m_quit:
3116    M_Quit_Draw ();
3117    break;
3118
3119  case m_serialconfig:
3120    M_SerialConfig_Draw ();
3121    break;
3122
3123  case m_modemconfig:
3124    M_ModemConfig_Draw ();
3125    break;
3126
3127  case m_lanconfig:
3128    M_LanConfig_Draw ();
3129    break;
3130
3131  case m_gameoptions:
3132    M_GameOptions_Draw ();
3133    break;
3134
3135  case m_search:
3136    M_Search_Draw ();
3137    break;
3138
3139  case m_slist:
3140    M_ServerList_Draw ();
3141    break;
3142  }
3143
3144  if (m_entersound)
3145  {
3146    S_LocalSound ("misc/menu2.wav");
3147    m_entersound = false;
3148  }
3149
3150  VID_UnlockBuffer ();
3151  S_ExtraUpdate ();
3152  VID_LockBuffer ();
3153}
3154
3155
3156void M_Keydown (int key)
3157{
3158  switch (m_state)
3159  {
3160  case m_none:
3161    return;
3162
3163  case m_main:
3164    M_Main_Key (key);
3165    return;
3166
3167  case m_singleplayer:
3168    M_SinglePlayer_Key (key);
3169    return;
3170
3171  case m_load:
3172    M_Load_Key (key);
3173    return;
3174
3175  case m_save:
3176    M_Save_Key (key);
3177    return;
3178
3179  case m_multiplayer:
3180    M_MultiPlayer_Key (key);
3181    return;
3182
3183  case m_setup:
3184    M_Setup_Key (key);
3185    return;
3186
3187  case m_net:
3188    M_Net_Key (key);
3189    return;
3190
3191  case m_options:
3192    M_Options_Key (key);
3193    return;
3194
3195  case m_keys:
3196    M_Keys_Key (key);
3197    return;
3198
3199  case m_video:
3200    M_Video_Key (key);
3201    return;
3202
3203  case m_help:
3204    M_Help_Key (key);
3205    return;
3206
3207  case m_quit:
3208    M_Quit_Key (key);
3209    return;
3210
3211  case m_serialconfig:
3212    M_SerialConfig_Key (key);
3213    return;
3214
3215  case m_modemconfig:
3216    M_ModemConfig_Key (key);
3217    return;
3218
3219  case m_lanconfig:
3220    M_LanConfig_Key (key);
3221    return;
3222
3223  case m_gameoptions:
3224    M_GameOptions_Key (key);
3225    return;
3226
3227  case m_search:
3228    M_Search_Key (key);
3229    break;
3230
3231  case m_slist:
3232    M_ServerList_Key (key);
3233    return;
3234  }
3235}
3236
3237
3238void M_ConfigureNetSubsystem(void)
3239{
3240// enable/disable net systems to match desired config
3241
3242  Cbuf_AddText ("stopdemo\n");
3243  if (SerialConfig || DirectConfig)
3244  {
3245    Cbuf_AddText ("com1 enable\n");
3246  }
3247
3248  if (IPXConfig || TCPIPConfig)
3249    net_hostport = lanConfig_port;
3250}
3251