• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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 
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 */
M_DrawCharacter(int cx,int line,int num)112 void M_DrawCharacter (int cx, int line, int num)
113 {
114   Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
115 }
116 
M_Print(int cx,int cy,const char * str)117 void 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 
M_PrintWhite(int cx,int cy,const char * str)127 void 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 
M_DrawTransPic(int x,int y,qpic_t * pic)137 void M_DrawTransPic (int x, int y, qpic_t *pic)
138 {
139   Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
140 }
141 
M_DrawPic(int x,int y,qpic_t * pic)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 
M_BuildTranslationTable(int top,int bottom)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 
M_DrawTransPicTranslate(int x,int y,qpic_t * pic)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 
M_DrawTextBox(int x,int y,int width,int lines)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 */
M_ToggleMenu_f(void)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 
M_Menu_Main_f(void)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 
M_Main_Draw(void)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 
M_Main_Key(int key)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 
M_Menu_SinglePlayer_f(void)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 
M_SinglePlayer_Draw(void)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 
M_SinglePlayer_Key(int key)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 
M_ScanSaves(void)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 
M_Menu_Load_f(void)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 
M_Menu_Save_f(void)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 
M_Load_Draw(void)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 
M_Save_Draw(void)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 
M_Load_Key(int k)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 
M_Save_Key(int k)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 
M_Menu_MultiPlayer_f(void)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 
M_MultiPlayer_Draw(void)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 
M_MultiPlayer_Key(int key)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 
M_Menu_Setup_f(void)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 
M_Setup_Draw(void)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 
M_Setup_Key(int k)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 const 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 
M_Menu_Net_f(void)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 
M_Net_Draw(void)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 
M_Net_Key(int k)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 
M_Menu_Options_f(void)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 
M_AdjustSliders(int dir)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 
M_DrawSlider(int x,int y,float range)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 ((int) (x + (SLIDER_RANGE-1)*8 * range), y, 131);
1162 }
1163 
M_DrawCheckbox(int x,int y,int on)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 
M_Options_Draw(void)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, (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 
M_Options_Key(int k)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 const 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 
M_Menu_Keys_f(void)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 
M_FindKeysForCommand(const char * command,int * twokeys)1350 void 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 
M_UnbindCommand(const char * command)1376 void 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 
M_Keys_Draw(void)1395 void 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 
M_Keys_Key(int k)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 >= (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 
M_Menu_Video_f(void)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 
M_Video_Draw(void)1517 void M_Video_Draw (void)
1518 {
1519   (*vid_menudrawfn) ();
1520 }
1521 
1522 
M_Video_Key(int key)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 
M_Menu_Help_f(void)1535 void 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 
M_Help_Draw(void)1554 void M_Help_Draw (void)
1555 {
1556   M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
1557 }
1558 
1559 
M_Help_Key(int key)1560 void 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 
1588 int        msgNumber;
1589 int        m_quit_prevstate;
1590 qboolean    wasInMenus;
1591 
1592 #ifndef    _WIN32
1593 const 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 
M_Menu_Quit_f(void)1638 void 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 
M_Quit_Key(int key)1651 void 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 
M_Quit_Draw(void)1684 void 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 
1734 int        serialConfig_cursor;
1735 int        serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
1736 #define    NUM_SERIALCONFIG_CMDS    6
1737 
1738 static int ISA_uarts[]    = {0x3f8,0x2f8,0x3e8,0x2e8};
1739 static int ISA_IRQs[]    = {4,3,4,3};
1740 int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
1741 
1742 int        serialConfig_comport;
1743 int        serialConfig_irq ;
1744 int        serialConfig_baud;
1745 char    serialConfig_phone[16];
1746 
M_Menu_SerialConfig_f(void)1747 void 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 
M_SerialConfig_Draw(void)1788 void 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 
M_SerialConfig_Key(int key)1855 void 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;
1913 forward:
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 
2025 int        modemConfig_cursor;
2026 int        modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
2027 #define NUM_MODEMCONFIG_CMDS    5
2028 
2029 char    modemConfig_dialing;
2030 char    modemConfig_clear [16];
2031 char    modemConfig_init [32];
2032 char    modemConfig_hangup [16];
2033 
M_Menu_ModemConfig_f(void)2034 void 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 
M_ModemConfig_Draw(void)2043 void 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 
M_ModemConfig_Key(int key)2084 void 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 
2197 int        lanConfig_cursor = -1;
2198 int        lanConfig_cursor_table [] = {72, 92, 124};
2199 #define NUM_LANCONFIG_CMDS    3
2200 
2201 int     lanConfig_port;
2202 char    lanConfig_portname[6];
2203 char    lanConfig_joinname[22];
2204 
M_Menu_LanConfig_f(void)2205 void 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 
M_LanConfig_Draw(void)2227 void 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 
M_LanConfig_Key(int key)2286 void 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 
2401 typedef struct
2402 {
2403   const char    *name;
2404   const char    *description;
2405 } level_t;
2406 
2407 level_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
2456 level_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
2485 level_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 
2506 typedef struct
2507 {
2508   const char    *description;
2509   int        firstLevel;
2510   int        levels;
2511 } episode_t;
2512 
2513 episode_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
2525 episode_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
2537 episode_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 
2545 int    startepisode;
2546 int    startlevel;
2547 int maxplayers;
2548 qboolean m_serverInfoMessage = false;
2549 double m_serverInfoMessageTime;
2550 
M_Menu_GameOptions_f(void)2551 void 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 
2563 int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
2564 #define    NUM_GAMEOPTIONS    9
2565 int        gameoptions_cursor;
2566 
M_GameOptions_Draw(void)2567 void 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 
M_NetStart_Change(int dir)2692 void 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 
M_GameOptions_Key(int key)2794 void 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 
2858 qboolean    searchComplete = false;
2859 double        searchCompleteTime;
2860 
M_Menu_Search_f(void)2861 void 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 
M_Search_Draw(void)2874 void 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 
M_Search_Key(int key)2911 void M_Search_Key (int key)
2912 {
2913 }
2914 
2915 //=============================================================================
2916 /* SLIST MENU */
2917 
2918 int        slist_cursor;
2919 qboolean slist_sorted;
2920 
M_Menu_ServerList_f(void)2921 void 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 
M_ServerList_Draw(void)2933 void 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 
M_ServerList_Key(int k)2974 void 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 
M_Init(void)3022 void 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 
M_Draw(void)3040 void 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 
M_Keydown(int key)3156 void 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 
M_ConfigureNetSubsystem(void)3238 void 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