64-bit fixes.
[AROS-Contrib.git] / Games / Quake / menu.c
blob0b9fa3e9c04a6834d86d3766083eac02fbd48520
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 #include "quakedef.h"
22 #ifdef _WIN32
23 #include "winquake.h"
24 #endif
26 void (*vid_menudrawfn)(void);
27 void (*vid_menukeyfn)(int key);
29 enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
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);
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);
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);
88 qboolean m_entersound; // play after drawing a frame, so caching
89 // won't disrupt the sound
90 qboolean m_recursiveDraw;
92 int m_return_state;
93 qboolean m_return_onerror;
94 char m_return_reason [32];
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)
103 void M_ConfigureNetSubsystem(void);
106 ================
107 M_DrawCharacter
109 Draws one solid graphics character
110 ================
112 void M_DrawCharacter (int cx, int line, int num)
114 Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
117 void M_Print (int cx, int cy, char *str)
119 while (*str)
121 M_DrawCharacter (cx, cy, (*str)+128);
122 str++;
123 cx += 8;
127 void M_PrintWhite (int cx, int cy, char *str)
129 while (*str)
131 M_DrawCharacter (cx, cy, *str);
132 str++;
133 cx += 8;
137 void M_DrawTransPic (int x, int y, qpic_t *pic)
139 Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
142 void M_DrawPic (int x, int y, qpic_t *pic)
144 Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
147 byte identityTable[256];
148 byte translationTable[256];
150 void M_BuildTranslationTable(int top, int bottom)
152 int j;
153 byte *dest, *source;
155 for (j = 0; j < 256; j++)
156 identityTable[j] = j;
157 dest = translationTable;
158 source = identityTable;
159 memcpy (dest, source, 256);
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];
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];
175 void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
177 Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
181 void M_DrawTextBox (int x, int y, int width, int lines)
183 qpic_t *p;
184 int cx, cy;
185 int n;
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++)
195 cy += 8;
196 M_DrawTransPic (cx, cy, p);
198 p = Draw_CachePic ("gfx/box_bl.lmp");
199 M_DrawTransPic (cx, cy+8, p);
201 // draw middle
202 cx += 8;
203 while (width > 0)
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++)
211 cy += 8;
212 if (n == 1)
213 p = Draw_CachePic ("gfx/box_mm2.lmp");
214 M_DrawTransPic (cx, cy, p);
216 p = Draw_CachePic ("gfx/box_bm.lmp");
217 M_DrawTransPic (cx, cy+8, p);
218 width -= 2;
219 cx += 16;
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++)
229 cy += 8;
230 M_DrawTransPic (cx, cy, p);
232 p = Draw_CachePic ("gfx/box_br.lmp");
233 M_DrawTransPic (cx, cy+8, p);
236 //=============================================================================
238 int m_save_demonum;
241 ================
242 M_ToggleMenu_f
243 ================
245 void M_ToggleMenu_f (void)
247 m_entersound = true;
249 if (key_dest == key_menu)
251 if (m_state != m_main)
253 M_Menu_Main_f ();
254 return;
256 key_dest = key_game;
257 m_state = m_none;
258 return;
260 if (key_dest == key_console)
262 Con_ToggleConsole_f ();
264 else
266 M_Menu_Main_f ();
271 //=============================================================================
272 /* MAIN MENU */
274 int m_main_cursor;
275 #define MAIN_ITEMS 5
278 void M_Menu_Main_f (void)
280 if (key_dest != key_menu)
282 m_save_demonum = cls.demonum;
283 cls.demonum = -1;
285 key_dest = key_menu;
286 m_state = m_main;
287 m_entersound = true;
291 void M_Main_Draw (void)
293 int f;
294 qpic_t *p;
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") );
301 f = (int)(host_time * 10)%6;
303 M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
307 void M_Main_Key (int key)
309 switch (key)
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;
319 case K_DOWNARROW:
320 S_LocalSound ("misc/menu1.wav");
321 if (++m_main_cursor >= MAIN_ITEMS)
322 m_main_cursor = 0;
323 break;
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;
331 case K_ENTER:
332 m_entersound = true;
334 switch (m_main_cursor)
336 case 0:
337 M_Menu_SinglePlayer_f ();
338 break;
340 case 1:
341 M_Menu_MultiPlayer_f ();
342 break;
344 case 2:
345 M_Menu_Options_f ();
346 break;
348 case 3:
349 M_Menu_Help_f ();
350 break;
352 case 4:
353 M_Menu_Quit_f ();
354 break;
359 //=============================================================================
360 /* SINGLE PLAYER MENU */
362 int m_singleplayer_cursor;
363 #define SINGLEPLAYER_ITEMS 3
366 void M_Menu_SinglePlayer_f (void)
368 key_dest = key_menu;
369 m_state = m_singleplayer;
370 m_entersound = true;
374 void M_SinglePlayer_Draw (void)
376 int f;
377 qpic_t *p;
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") );
384 f = (int)(host_time * 10)%6;
386 M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
390 void M_SinglePlayer_Key (int key)
392 switch (key)
394 case K_ESCAPE:
395 M_Menu_Main_f ();
396 break;
398 case K_DOWNARROW:
399 S_LocalSound ("misc/menu1.wav");
400 if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
401 m_singleplayer_cursor = 0;
402 break;
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;
410 case K_ENTER:
411 m_entersound = true;
413 switch (m_singleplayer_cursor)
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;
426 case 1:
427 M_Menu_Load_f ();
428 break;
430 case 2:
431 M_Menu_Save_f ();
432 break;
437 //=============================================================================
438 /* LOAD/SAVE MENU */
440 int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES
442 #define MAX_SAVEGAMES 12
443 char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
444 int loadable[MAX_SAVEGAMES];
446 void M_ScanSaves (void)
448 int i, j;
449 char name[MAX_OSPATH];
450 FILE *f;
451 int version;
453 for (i=0 ; i<MAX_SAVEGAMES ; i++)
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);
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);
474 void M_Menu_Load_f (void)
476 m_entersound = true;
477 m_state = m_load;
478 key_dest = key_menu;
479 M_ScanSaves ();
483 void M_Menu_Save_f (void)
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 ();
498 void M_Load_Draw (void)
500 int i;
501 qpic_t *p;
503 p = Draw_CachePic ("gfx/p_load.lmp");
504 M_DrawPic ( (320-p->width)/2, 4, p);
506 for (i=0 ; i< MAX_SAVEGAMES; i++)
507 M_Print (16, 32 + 8*i, m_filenames[i]);
509 // line cursor
510 M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
514 void M_Save_Draw (void)
516 int i;
517 qpic_t *p;
519 p = Draw_CachePic ("gfx/p_save.lmp");
520 M_DrawPic ( (320-p->width)/2, 4, p);
522 for (i=0 ; i<MAX_SAVEGAMES ; i++)
523 M_Print (16, 32 + 8*i, m_filenames[i]);
525 // line cursor
526 M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
530 void M_Load_Key (int k)
532 switch (k)
534 case K_ESCAPE:
535 M_Menu_SinglePlayer_f ();
536 break;
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;
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 ();
549 // issue the load command
550 Cbuf_AddText (va ("load s%i\n", load_cursor) );
551 return;
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;
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;
572 void M_Save_Key (int k)
574 switch (k)
576 case K_ESCAPE:
577 M_Menu_SinglePlayer_f ();
578 break;
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;
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;
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;
604 //=============================================================================
605 /* MULTIPLAYER MENU */
607 int m_multiplayer_cursor;
608 #define MULTIPLAYER_ITEMS 3
611 void M_Menu_MultiPlayer_f (void)
613 key_dest = key_menu;
614 m_state = m_multiplayer;
615 m_entersound = true;
619 void M_MultiPlayer_Draw (void)
621 int f;
622 qpic_t *p;
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") );
629 f = (int)(host_time * 10)%6;
631 M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
633 if (serialAvailable || ipxAvailable || tcpipAvailable)
634 return;
635 M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
639 void M_MultiPlayer_Key (int key)
641 switch (key)
643 case K_ESCAPE:
644 M_Menu_Main_f ();
645 break;
647 case K_DOWNARROW:
648 S_LocalSound ("misc/menu1.wav");
649 if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
650 m_multiplayer_cursor = 0;
651 break;
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;
659 case K_ENTER:
660 m_entersound = true;
661 switch (m_multiplayer_cursor)
663 case 0:
664 if (serialAvailable || ipxAvailable || tcpipAvailable)
665 M_Menu_Net_f ();
666 break;
668 case 1:
669 if (serialAvailable || ipxAvailable || tcpipAvailable)
670 M_Menu_Net_f ();
671 break;
673 case 2:
674 M_Menu_Setup_f ();
675 break;
680 //=============================================================================
681 /* SETUP MENU */
683 int setup_cursor = 4;
684 int setup_cursor_table[] = {40, 56, 80, 104, 140};
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;
693 #define NUM_SETUP_CMDS 5
695 void M_Menu_Setup_f (void)
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;
707 void M_Setup_Draw (void)
709 qpic_t *p;
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);
715 M_Print (64, 40, "Hostname");
716 M_DrawTextBox (160, 32, 16, 1);
717 M_Print (168, 40, setup_hostname);
719 M_Print (64, 56, "Your name");
720 M_DrawTextBox (160, 48, 16, 1);
721 M_Print (168, 56, setup_myname);
723 M_Print (64, 80, "Shirt color");
724 M_Print (64, 104, "Pants color");
726 M_DrawTextBox (64, 140-8, 14, 1);
727 M_Print (72, 140, "Accept Changes");
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);
735 M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
737 if (setup_cursor == 0)
738 M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
740 if (setup_cursor == 1)
741 M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
745 void M_Setup_Key (int k)
747 int l;
749 switch (k)
751 case K_ESCAPE:
752 M_Menu_MultiPlayer_f ();
753 break;
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;
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;
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;
789 case K_ENTER:
790 if (setup_cursor == 0 || setup_cursor == 1)
791 return;
793 if (setup_cursor == 2 || setup_cursor == 3)
794 goto forward;
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;
807 case K_BACKSPACE:
808 if (setup_cursor == 0)
810 if (strlen(setup_hostname))
811 setup_hostname[strlen(setup_hostname)-1] = 0;
814 if (setup_cursor == 1)
816 if (strlen(setup_myname))
817 setup_myname[strlen(setup_myname)-1] = 0;
819 break;
821 default:
822 if (k < 32 || k > 127)
823 break;
824 if (setup_cursor == 0)
826 l = strlen(setup_hostname);
827 if (l < 15)
829 setup_hostname[l+1] = 0;
830 setup_hostname[l] = k;
833 if (setup_cursor == 1)
835 l = strlen(setup_myname);
836 if (l < 15)
838 setup_myname[l+1] = 0;
839 setup_myname[l] = k;
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;
854 //=============================================================================
855 /* NET MENU */
857 int m_net_cursor;
858 int m_net_items;
859 int m_net_saveHeight;
861 char *net_helpMessage [] =
863 /* .........1.........2.... */
864 " ",
865 " Two computers connected",
866 " through two modems. ",
867 " ",
869 " ",
870 " Two computers connected",
871 " by a null-modem cable. ",
872 " ",
874 " Novell network LANs ",
875 " or Windows 95 DOS-box. ",
876 " ",
877 "(LAN=Local Area Network)",
879 " Commonly used to play ",
880 " over the Internet, but ",
881 " also used on a Local ",
882 " Area Network. "
885 void M_Menu_Net_f (void)
887 key_dest = key_menu;
888 m_state = m_net;
889 m_entersound = true;
890 m_net_items = 4;
892 if (m_net_cursor >= m_net_items)
893 m_net_cursor = 0;
894 m_net_cursor--;
895 M_Net_Key (K_DOWNARROW);
899 void M_Net_Draw (void)
901 int f;
902 qpic_t *p;
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);
908 f = 32;
910 if (serialAvailable)
912 p = Draw_CachePic ("gfx/netmen1.lmp");
914 else
916 #ifdef _WIN32
917 p = NULL;
918 #else
919 p = Draw_CachePic ("gfx/dim_modm.lmp");
920 #endif
923 if (p)
924 M_DrawTransPic (72, f, p);
926 f += 19;
928 if (serialAvailable)
930 p = Draw_CachePic ("gfx/netmen2.lmp");
932 else
934 #ifdef _WIN32
935 p = NULL;
936 #else
937 p = Draw_CachePic ("gfx/dim_drct.lmp");
938 #endif
941 if (p)
942 M_DrawTransPic (72, f, p);
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);
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);
958 if (m_net_items == 5) // JDC, could just be removed
960 f += 19;
961 p = Draw_CachePic ("gfx/netmen5.lmp");
962 M_DrawTransPic (72, f, p);
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]);
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 ) ) );
978 void M_Net_Key (int k)
980 again:
981 switch (k)
983 case K_ESCAPE:
984 M_Menu_MultiPlayer_f ();
985 break;
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;
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;
999 case K_ENTER:
1000 m_entersound = true;
1002 switch (m_net_cursor)
1004 case 0:
1005 M_Menu_SerialConfig_f ();
1006 break;
1008 case 1:
1009 M_Menu_SerialConfig_f ();
1010 break;
1012 case 2:
1013 M_Menu_LanConfig_f ();
1014 break;
1016 case 3:
1017 M_Menu_LanConfig_f ();
1018 break;
1020 case 4:
1021 // multiprotocol
1022 break;
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;
1036 //=============================================================================
1037 /* OPTIONS MENU */
1039 #ifdef _WIN32
1040 #define OPTIONS_ITEMS 14
1041 #else
1042 #define OPTIONS_ITEMS 13
1043 #endif
1045 #define SLIDER_RANGE 10
1047 int options_cursor;
1049 void M_Menu_Options_f (void)
1051 key_dest = key_menu;
1052 m_state = m_options;
1053 m_entersound = true;
1055 #ifdef _WIN32
1056 if ((options_cursor == 13) && (modestate != MS_WINDOWED))
1058 options_cursor = 0;
1060 #endif
1064 void M_AdjustSliders (int dir)
1066 S_LocalSound ("misc/menu3.wav");
1068 switch (options_cursor)
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;
1115 case 8: // allways run
1116 if (cl_forwardspeed.value > 200)
1118 Cvar_SetValue ("cl_forwardspeed", 200);
1119 Cvar_SetValue ("cl_backspeed", 200);
1121 else
1123 Cvar_SetValue ("cl_forwardspeed", 400);
1124 Cvar_SetValue ("cl_backspeed", 400);
1126 break;
1128 case 9: // invert mouse
1129 Cvar_SetValue ("m_pitch", -m_pitch.value);
1130 break;
1132 case 10: // lookspring
1133 Cvar_SetValue ("lookspring", !lookspring.value);
1134 break;
1136 case 11: // lookstrafe
1137 Cvar_SetValue ("lookstrafe", !lookstrafe.value);
1138 break;
1140 #ifdef _WIN32
1141 case 13: // _windowed_mouse
1142 Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
1143 break;
1144 #endif
1149 void M_DrawSlider (int x, int y, float range)
1151 int i;
1153 if (range < 0)
1154 range = 0;
1155 if (range > 1)
1156 range = 1;
1157 M_DrawCharacter (x-8, y, 128);
1158 for (i=0 ; i<SLIDER_RANGE ; i++)
1159 M_DrawCharacter (x + i*8, y, 129);
1160 M_DrawCharacter (x+i*8, y, 130);
1161 M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
1164 void M_DrawCheckbox (int x, int y, int on)
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");
1178 void M_Options_Draw (void)
1180 float r;
1181 qpic_t *p;
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);
1187 M_Print (16, 32, " Customize controls");
1188 M_Print (16, 40, " Go to console");
1189 M_Print (16, 48, " Reset to defaults");
1191 M_Print (16, 56, " Screen size");
1192 r = (scr_viewsize.value - 30) / (120 - 30);
1193 M_DrawSlider (220, 56, r);
1195 M_Print (16, 64, " Brightness");
1196 r = (1.0 - v_gamma.value) / 0.5;
1197 M_DrawSlider (220, 64, r);
1199 M_Print (16, 72, " Mouse Speed");
1200 r = (sensitivity.value - 1)/10;
1201 M_DrawSlider (220, 72, r);
1203 M_Print (16, 80, " CD Music Volume");
1204 r = bgmvolume.value;
1205 M_DrawSlider (220, 80, r);
1207 M_Print (16, 88, " Sound Volume");
1208 r = volume.value;
1209 M_DrawSlider (220, 88, r);
1211 M_Print (16, 96, " Always Run");
1212 M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
1214 M_Print (16, 104, " Invert Mouse");
1215 M_DrawCheckbox (220, 104, m_pitch.value < 0);
1217 M_Print (16, 112, " Lookspring");
1218 M_DrawCheckbox (220, 112, lookspring.value);
1220 M_Print (16, 120, " Lookstrafe");
1221 M_DrawCheckbox (220, 120, lookstrafe.value);
1223 if (vid_menudrawfn)
1224 M_Print (16, 128, " Video Options");
1226 #ifdef _WIN32
1227 if (modestate == MS_WINDOWED)
1229 M_Print (16, 136, " Use Mouse");
1230 M_DrawCheckbox (220, 136, _windowed_mouse.value);
1232 #endif
1234 // cursor
1235 M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
1239 void M_Options_Key (int k)
1241 switch (k)
1243 case K_ESCAPE:
1244 M_Menu_Main_f ();
1245 break;
1247 case K_ENTER:
1248 m_entersound = true;
1249 switch (options_cursor)
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;
1268 return;
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;
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;
1284 case K_LEFTARROW:
1285 M_AdjustSliders (-1);
1286 break;
1288 case K_RIGHTARROW:
1289 M_AdjustSliders (1);
1290 break;
1293 if (options_cursor == 12 && vid_menudrawfn == NULL)
1295 if (k == K_UPARROW)
1296 options_cursor = 11;
1297 else
1298 options_cursor = 0;
1301 #ifdef _WIN32
1302 if ((options_cursor == 13) && (modestate != MS_WINDOWED))
1304 if (k == K_UPARROW)
1305 options_cursor = 12;
1306 else
1307 options_cursor = 0;
1309 #endif
1312 //=============================================================================
1313 /* KEYS MENU */
1315 char *bindnames[][2] =
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"}
1337 #define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0]))
1339 int keys_cursor;
1340 int bind_grab;
1342 void M_Menu_Keys_f (void)
1344 key_dest = key_menu;
1345 m_state = m_keys;
1346 m_entersound = true;
1350 void M_FindKeysForCommand (char *command, int *twokeys)
1352 int count;
1353 int j;
1354 int l;
1355 char *b;
1357 twokeys[0] = twokeys[1] = -1;
1358 l = strlen(command);
1359 count = 0;
1361 for (j=0 ; j<256 ; j++)
1363 b = keybindings[j];
1364 if (!b)
1365 continue;
1366 if (!strncmp (b, command, l) )
1368 twokeys[count] = j;
1369 count++;
1370 if (count == 2)
1371 break;
1376 void M_UnbindCommand (char *command)
1378 int j;
1379 int l;
1380 char *b;
1382 l = strlen(command);
1384 for (j=0 ; j<256 ; j++)
1386 b = keybindings[j];
1387 if (!b)
1388 continue;
1389 if (!strncmp (b, command, l) )
1390 Key_SetBinding (j, "");
1395 void M_Keys_Draw (void)
1397 int i;
1398 int keys[2];
1399 char *name;
1400 int x, y;
1401 qpic_t *p;
1403 p = Draw_CachePic ("gfx/ttl_cstm.lmp");
1404 M_DrawPic ( (320-p->width)/2, 4, p);
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");
1411 // search for known bindings
1412 for (i=0 ; i<NUMCOMMANDS ; i++)
1414 y = 48 + 8*i;
1416 M_Print (16, y, bindnames[i][1]);
1418 M_FindKeysForCommand (bindnames[i][0], keys);
1420 if (keys[0] == -1)
1422 M_Print (140, y, "???");
1424 else
1426 name = Key_KeynumToString (keys[0]);
1427 M_Print (140, y, name);
1428 x = strlen(name) * 8;
1429 if (keys[1] != -1)
1431 M_Print (140 + x + 8, y, "or");
1432 M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
1437 if (bind_grab)
1438 M_DrawCharacter (130, 48 + keys_cursor*8, '=');
1439 else
1440 M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
1444 void M_Keys_Key (int k)
1446 char cmd[80];
1447 int keys[2];
1449 if (bind_grab)
1450 { // defining a key
1451 S_LocalSound ("misc/menu1.wav");
1452 if (k == K_ESCAPE)
1454 bind_grab = false;
1456 else if (k != '`')
1458 sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
1459 Cbuf_InsertText (cmd);
1462 bind_grab = false;
1463 return;
1466 switch (k)
1468 case K_ESCAPE:
1469 M_Menu_Options_f ();
1470 break;
1472 case K_LEFTARROW:
1473 case K_UPARROW:
1474 S_LocalSound ("misc/menu1.wav");
1475 keys_cursor--;
1476 if (keys_cursor < 0)
1477 keys_cursor = NUMCOMMANDS-1;
1478 break;
1480 case K_DOWNARROW:
1481 case K_RIGHTARROW:
1482 S_LocalSound ("misc/menu1.wav");
1483 keys_cursor++;
1484 if (keys_cursor >= NUMCOMMANDS)
1485 keys_cursor = 0;
1486 break;
1488 case K_ENTER: // go into bind mode
1489 M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
1490 S_LocalSound ("misc/menu2.wav");
1491 if (keys[1] != -1)
1492 M_UnbindCommand (bindnames[keys_cursor][0]);
1493 bind_grab = true;
1494 break;
1496 case K_BACKSPACE: // delete bindings
1497 case K_DEL: // delete bindings
1498 S_LocalSound ("misc/menu2.wav");
1499 M_UnbindCommand (bindnames[keys_cursor][0]);
1500 break;
1504 //=============================================================================
1505 /* VIDEO MENU */
1507 void M_Menu_Video_f (void)
1509 key_dest = key_menu;
1510 m_state = m_video;
1511 m_entersound = true;
1515 void M_Video_Draw (void)
1517 (*vid_menudrawfn) ();
1521 void M_Video_Key (int key)
1523 (*vid_menukeyfn) (key);
1526 //=============================================================================
1527 /* HELP MENU */
1529 int help_page;
1530 #define NUM_HELP_PAGES 6
1533 void M_Menu_Help_f (void)
1535 key_dest = key_menu;
1536 m_state = m_help;
1537 m_entersound = true;
1538 help_page = 0;
1543 void M_Help_Draw (void)
1545 M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
1549 void M_Help_Key (int key)
1551 switch (key)
1553 case K_ESCAPE:
1554 M_Menu_Main_f ();
1555 break;
1557 case K_UPARROW:
1558 case K_RIGHTARROW:
1559 m_entersound = true;
1560 if (++help_page >= NUM_HELP_PAGES)
1561 help_page = 0;
1562 break;
1564 case K_DOWNARROW:
1565 case K_LEFTARROW:
1566 m_entersound = true;
1567 if (--help_page < 0)
1568 help_page = NUM_HELP_PAGES-1;
1569 break;
1574 //=============================================================================
1575 /* QUIT MENU */
1577 int msgNumber;
1578 int m_quit_prevstate;
1579 qboolean wasInMenus;
1581 #ifndef _WIN32
1582 char *quitMessage [] =
1584 /* .........1.........2.... */
1585 " Are you gonna quit ",
1586 " this game just like ",
1587 " everything else? ",
1588 " ",
1590 " Milord, methinks that ",
1591 " thou art a lowly ",
1592 " quitter. Is this true? ",
1593 " ",
1595 " Do I need to bust your ",
1596 " face open for trying ",
1597 " to quit? ",
1598 " ",
1600 " Man, I oughta smack you",
1601 " for trying to quit! ",
1602 " Press Y to get ",
1603 " smacked out. ",
1605 " Press Y to quit like a ",
1606 " big loser in life. ",
1607 " Press N to stay proud ",
1608 " and successful! ",
1610 " If you press Y to ",
1611 " quit, I will summon ",
1612 " Satan all over your ",
1613 " hard drive! ",
1615 " Um, Asmodeus dislikes ",
1616 " his children trying to ",
1617 " quit. Press Y to return",
1618 " to your Tinkertoys. ",
1620 " If you quit now, I'll ",
1621 " throw a blanket-party ",
1622 " for you next time! ",
1625 #endif
1627 void M_Menu_Quit_f (void)
1629 if (m_state == m_quit)
1630 return;
1631 wasInMenus = (key_dest == key_menu);
1632 key_dest = key_menu;
1633 m_quit_prevstate = m_state;
1634 m_state = m_quit;
1635 m_entersound = true;
1636 msgNumber = rand()&7;
1640 void M_Quit_Key (int key)
1642 switch (key)
1644 case K_ESCAPE:
1645 case 'n':
1646 case 'N':
1647 if (wasInMenus)
1649 m_state = m_quit_prevstate;
1650 m_entersound = true;
1652 else
1654 key_dest = key_game;
1655 m_state = m_none;
1657 break;
1659 case 'Y':
1660 case 'y':
1661 key_dest = key_console;
1662 Host_Quit_f ();
1663 break;
1665 default:
1666 break;
1672 void M_Quit_Draw (void)
1674 if (wasInMenus)
1676 m_state = m_quit_prevstate;
1677 m_recursiveDraw = true;
1678 M_Draw ();
1679 m_state = m_quit;
1682 #ifdef _WIN32
1683 M_DrawTextBox (0, 0, 38, 23);
1684 M_PrintWhite (16, 12, " Quake version 1.09 by id Software\n\n");
1685 M_PrintWhite (16, 28, "Programming Art \n");
1686 M_Print (16, 36, " John Carmack Adrian Carmack\n");
1687 M_Print (16, 44, " Michael Abrash Kevin Cloud\n");
1688 M_Print (16, 52, " John Cash Paul Steed\n");
1689 M_Print (16, 60, " Dave 'Zoid' Kirsch\n");
1690 M_PrintWhite (16, 68, "Design Biz\n");
1691 M_Print (16, 76, " John Romero Jay Wilbur\n");
1692 M_Print (16, 84, " Sandy Petersen Mike Wilson\n");
1693 M_Print (16, 92, " American McGee Donna Jackson\n");
1694 M_Print (16, 100, " Tim Willits Todd Hollenshead\n");
1695 M_PrintWhite (16, 108, "Support Projects\n");
1696 M_Print (16, 116, " Barrett Alexander Shawn Green\n");
1697 M_PrintWhite (16, 124, "Sound Effects\n");
1698 M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
1699 M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
1700 M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
1701 M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
1702 M_PrintWhite (16, 164, "registered trademark licensed to\n");
1703 M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
1704 M_PrintWhite (16, 180, "reserved. Press y to exit\n");
1705 #else
1706 M_DrawTextBox (56, 76, 24, 4);
1707 M_Print (64, 84, quitMessage[msgNumber*4+0]);
1708 M_Print (64, 92, quitMessage[msgNumber*4+1]);
1709 M_Print (64, 100, quitMessage[msgNumber*4+2]);
1710 M_Print (64, 108, quitMessage[msgNumber*4+3]);
1711 #endif
1714 //=============================================================================
1716 /* SERIAL CONFIG MENU */
1718 int serialConfig_cursor;
1719 int serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
1720 #define NUM_SERIALCONFIG_CMDS 6
1722 static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8};
1723 static int ISA_IRQs[] = {4,3,4,3};
1724 int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
1726 int serialConfig_comport;
1727 int serialConfig_irq ;
1728 int serialConfig_baud;
1729 char serialConfig_phone[16];
1731 void M_Menu_SerialConfig_f (void)
1733 int n;
1734 int port;
1735 int baudrate;
1736 qboolean useModem;
1738 key_dest = key_menu;
1739 m_state = m_serialconfig;
1740 m_entersound = true;
1741 if (JoiningGame && SerialConfig)
1742 serialConfig_cursor = 4;
1743 else
1744 serialConfig_cursor = 5;
1746 (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
1748 // map uart's port to COMx
1749 for (n = 0; n < 4; n++)
1750 if (ISA_uarts[n] == port)
1751 break;
1752 if (n == 4)
1754 n = 0;
1755 serialConfig_irq = 4;
1757 serialConfig_comport = n + 1;
1759 // map baudrate to index
1760 for (n = 0; n < 6; n++)
1761 if (serialConfig_baudrate[n] == baudrate)
1762 break;
1763 if (n == 6)
1764 n = 5;
1765 serialConfig_baud = n;
1767 m_return_onerror = false;
1768 m_return_reason[0] = 0;
1772 void M_SerialConfig_Draw (void)
1774 qpic_t *p;
1775 int basex;
1776 char *startJoin;
1777 char *directModem;
1779 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1780 p = Draw_CachePic ("gfx/p_multi.lmp");
1781 basex = (320-p->width)/2;
1782 M_DrawPic (basex, 4, p);
1784 if (StartingGame)
1785 startJoin = "New Game";
1786 else
1787 startJoin = "Join Game";
1788 if (SerialConfig)
1789 directModem = "Modem";
1790 else
1791 directModem = "Direct Connect";
1792 M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
1793 basex += 8;
1795 M_Print (basex, serialConfig_cursor_table[0], "Port");
1796 M_DrawTextBox (160, 40, 4, 1);
1797 M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
1799 M_Print (basex, serialConfig_cursor_table[1], "IRQ");
1800 M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
1801 M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
1803 M_Print (basex, serialConfig_cursor_table[2], "Baud");
1804 M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
1805 M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
1807 if (SerialConfig)
1809 M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
1810 if (JoiningGame)
1812 M_Print (basex, serialConfig_cursor_table[4], "Phone number");
1813 M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
1814 M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
1818 if (JoiningGame)
1820 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
1821 M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
1823 else
1825 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
1826 M_Print (basex+8, serialConfig_cursor_table[5], "OK");
1829 M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
1831 if (serialConfig_cursor == 4)
1832 M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
1834 if (*m_return_reason)
1835 M_PrintWhite (basex, 148, m_return_reason);
1839 void M_SerialConfig_Key (int key)
1841 int l;
1843 switch (key)
1845 case K_ESCAPE:
1846 M_Menu_Net_f ();
1847 break;
1849 case K_UPARROW:
1850 S_LocalSound ("misc/menu1.wav");
1851 serialConfig_cursor--;
1852 if (serialConfig_cursor < 0)
1853 serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
1854 break;
1856 case K_DOWNARROW:
1857 S_LocalSound ("misc/menu1.wav");
1858 serialConfig_cursor++;
1859 if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
1860 serialConfig_cursor = 0;
1861 break;
1863 case K_LEFTARROW:
1864 if (serialConfig_cursor > 2)
1865 break;
1866 S_LocalSound ("misc/menu3.wav");
1868 if (serialConfig_cursor == 0)
1870 serialConfig_comport--;
1871 if (serialConfig_comport == 0)
1872 serialConfig_comport = 4;
1873 serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1876 if (serialConfig_cursor == 1)
1878 serialConfig_irq--;
1879 if (serialConfig_irq == 6)
1880 serialConfig_irq = 5;
1881 if (serialConfig_irq == 1)
1882 serialConfig_irq = 7;
1885 if (serialConfig_cursor == 2)
1887 serialConfig_baud--;
1888 if (serialConfig_baud < 0)
1889 serialConfig_baud = 5;
1892 break;
1894 case K_RIGHTARROW:
1895 if (serialConfig_cursor > 2)
1896 break;
1897 forward:
1898 S_LocalSound ("misc/menu3.wav");
1900 if (serialConfig_cursor == 0)
1902 serialConfig_comport++;
1903 if (serialConfig_comport > 4)
1904 serialConfig_comport = 1;
1905 serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1908 if (serialConfig_cursor == 1)
1910 serialConfig_irq++;
1911 if (serialConfig_irq == 6)
1912 serialConfig_irq = 7;
1913 if (serialConfig_irq == 8)
1914 serialConfig_irq = 2;
1917 if (serialConfig_cursor == 2)
1919 serialConfig_baud++;
1920 if (serialConfig_baud > 5)
1921 serialConfig_baud = 0;
1924 break;
1926 case K_ENTER:
1927 if (serialConfig_cursor < 3)
1928 goto forward;
1930 m_entersound = true;
1932 if (serialConfig_cursor == 3)
1934 (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1936 M_Menu_ModemConfig_f ();
1937 break;
1940 if (serialConfig_cursor == 4)
1942 serialConfig_cursor = 5;
1943 break;
1946 // serialConfig_cursor == 5 (OK/CONNECT)
1947 (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1949 M_ConfigureNetSubsystem ();
1951 if (StartingGame)
1953 M_Menu_GameOptions_f ();
1954 break;
1957 m_return_state = m_state;
1958 m_return_onerror = true;
1959 key_dest = key_game;
1960 m_state = m_none;
1962 if (SerialConfig)
1963 Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
1964 else
1965 Cbuf_AddText ("connect\n");
1966 break;
1968 case K_BACKSPACE:
1969 if (serialConfig_cursor == 4)
1971 if (strlen(serialConfig_phone))
1972 serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
1974 break;
1976 default:
1977 if (key < 32 || key > 127)
1978 break;
1979 if (serialConfig_cursor == 4)
1981 l = strlen(serialConfig_phone);
1982 if (l < 15)
1984 serialConfig_phone[l+1] = 0;
1985 serialConfig_phone[l] = key;
1990 if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
1992 if (key == K_UPARROW)
1993 serialConfig_cursor = 2;
1994 else
1995 serialConfig_cursor = 5;
1998 if (SerialConfig && StartingGame && serialConfig_cursor == 4)
2000 if (key == K_UPARROW)
2001 serialConfig_cursor = 3;
2002 else
2003 serialConfig_cursor = 5;
2007 //=============================================================================
2008 /* MODEM CONFIG MENU */
2010 int modemConfig_cursor;
2011 int modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
2012 #define NUM_MODEMCONFIG_CMDS 5
2014 char modemConfig_dialing;
2015 char modemConfig_clear [16];
2016 char modemConfig_init [32];
2017 char modemConfig_hangup [16];
2019 void M_Menu_ModemConfig_f (void)
2021 key_dest = key_menu;
2022 m_state = m_modemconfig;
2023 m_entersound = true;
2024 (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
2028 void M_ModemConfig_Draw (void)
2030 qpic_t *p;
2031 int basex;
2033 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2034 p = Draw_CachePic ("gfx/p_multi.lmp");
2035 basex = (320-p->width)/2;
2036 M_DrawPic (basex, 4, p);
2037 basex += 8;
2039 if (modemConfig_dialing == 'P')
2040 M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
2041 else
2042 M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
2044 M_Print (basex, modemConfig_cursor_table[1], "Clear");
2045 M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
2046 M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
2047 if (modemConfig_cursor == 1)
2048 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
2050 M_Print (basex, modemConfig_cursor_table[2], "Init");
2051 M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
2052 M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
2053 if (modemConfig_cursor == 2)
2054 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
2056 M_Print (basex, modemConfig_cursor_table[3], "Hangup");
2057 M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
2058 M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
2059 if (modemConfig_cursor == 3)
2060 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
2062 M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
2063 M_Print (basex+8, modemConfig_cursor_table[4], "OK");
2065 M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
2069 void M_ModemConfig_Key (int key)
2071 int l;
2073 switch (key)
2075 case K_ESCAPE:
2076 M_Menu_SerialConfig_f ();
2077 break;
2079 case K_UPARROW:
2080 S_LocalSound ("misc/menu1.wav");
2081 modemConfig_cursor--;
2082 if (modemConfig_cursor < 0)
2083 modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
2084 break;
2086 case K_DOWNARROW:
2087 S_LocalSound ("misc/menu1.wav");
2088 modemConfig_cursor++;
2089 if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
2090 modemConfig_cursor = 0;
2091 break;
2093 case K_LEFTARROW:
2094 case K_RIGHTARROW:
2095 if (modemConfig_cursor == 0)
2097 if (modemConfig_dialing == 'P')
2098 modemConfig_dialing = 'T';
2099 else
2100 modemConfig_dialing = 'P';
2101 S_LocalSound ("misc/menu1.wav");
2103 break;
2105 case K_ENTER:
2106 if (modemConfig_cursor == 0)
2108 if (modemConfig_dialing == 'P')
2109 modemConfig_dialing = 'T';
2110 else
2111 modemConfig_dialing = 'P';
2112 m_entersound = true;
2115 if (modemConfig_cursor == 4)
2117 (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
2118 m_entersound = true;
2119 M_Menu_SerialConfig_f ();
2121 break;
2123 case K_BACKSPACE:
2124 if (modemConfig_cursor == 1)
2126 if (strlen(modemConfig_clear))
2127 modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
2130 if (modemConfig_cursor == 2)
2132 if (strlen(modemConfig_init))
2133 modemConfig_init[strlen(modemConfig_init)-1] = 0;
2136 if (modemConfig_cursor == 3)
2138 if (strlen(modemConfig_hangup))
2139 modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
2141 break;
2143 default:
2144 if (key < 32 || key > 127)
2145 break;
2147 if (modemConfig_cursor == 1)
2149 l = strlen(modemConfig_clear);
2150 if (l < 15)
2152 modemConfig_clear[l+1] = 0;
2153 modemConfig_clear[l] = key;
2157 if (modemConfig_cursor == 2)
2159 l = strlen(modemConfig_init);
2160 if (l < 29)
2162 modemConfig_init[l+1] = 0;
2163 modemConfig_init[l] = key;
2167 if (modemConfig_cursor == 3)
2169 l = strlen(modemConfig_hangup);
2170 if (l < 15)
2172 modemConfig_hangup[l+1] = 0;
2173 modemConfig_hangup[l] = key;
2179 //=============================================================================
2180 /* LAN CONFIG MENU */
2182 int lanConfig_cursor = -1;
2183 int lanConfig_cursor_table [] = {72, 92, 124};
2184 #define NUM_LANCONFIG_CMDS 3
2186 int lanConfig_port;
2187 char lanConfig_portname[6];
2188 char lanConfig_joinname[22];
2190 void M_Menu_LanConfig_f (void)
2192 key_dest = key_menu;
2193 m_state = m_lanconfig;
2194 m_entersound = true;
2195 if (lanConfig_cursor == -1)
2197 if (JoiningGame && TCPIPConfig)
2198 lanConfig_cursor = 2;
2199 else
2200 lanConfig_cursor = 1;
2202 if (StartingGame && lanConfig_cursor == 2)
2203 lanConfig_cursor = 1;
2204 lanConfig_port = DEFAULTnet_hostport;
2205 sprintf(lanConfig_portname, "%u", lanConfig_port);
2207 m_return_onerror = false;
2208 m_return_reason[0] = 0;
2212 void M_LanConfig_Draw (void)
2214 qpic_t *p;
2215 int basex;
2216 char *startJoin;
2217 char *protocol;
2219 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2220 p = Draw_CachePic ("gfx/p_multi.lmp");
2221 basex = (320-p->width)/2;
2222 M_DrawPic (basex, 4, p);
2224 if (StartingGame)
2225 startJoin = "New Game";
2226 else
2227 startJoin = "Join Game";
2228 if (IPXConfig)
2229 protocol = "IPX";
2230 else
2231 protocol = "TCP/IP";
2232 M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
2233 basex += 8;
2235 M_Print (basex, 52, "Address:");
2236 if (IPXConfig)
2237 M_Print (basex+9*8, 52, my_ipx_address);
2238 else
2239 M_Print (basex+9*8, 52, my_tcpip_address);
2241 M_Print (basex, lanConfig_cursor_table[0], "Port");
2242 M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
2243 M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
2245 if (JoiningGame)
2247 M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
2248 M_Print (basex, 108, "Join game at:");
2249 M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
2250 M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
2252 else
2254 M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
2255 M_Print (basex+8, lanConfig_cursor_table[1], "OK");
2258 M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
2260 if (lanConfig_cursor == 0)
2261 M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
2263 if (lanConfig_cursor == 2)
2264 M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
2266 if (*m_return_reason)
2267 M_PrintWhite (basex, 148, m_return_reason);
2271 void M_LanConfig_Key (int key)
2273 int l;
2275 switch (key)
2277 case K_ESCAPE:
2278 M_Menu_Net_f ();
2279 break;
2281 case K_UPARROW:
2282 S_LocalSound ("misc/menu1.wav");
2283 lanConfig_cursor--;
2284 if (lanConfig_cursor < 0)
2285 lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
2286 break;
2288 case K_DOWNARROW:
2289 S_LocalSound ("misc/menu1.wav");
2290 lanConfig_cursor++;
2291 if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
2292 lanConfig_cursor = 0;
2293 break;
2295 case K_ENTER:
2296 if (lanConfig_cursor == 0)
2297 break;
2299 m_entersound = true;
2301 M_ConfigureNetSubsystem ();
2303 if (lanConfig_cursor == 1)
2305 if (StartingGame)
2307 M_Menu_GameOptions_f ();
2308 break;
2310 M_Menu_Search_f();
2311 break;
2314 if (lanConfig_cursor == 2)
2316 m_return_state = m_state;
2317 m_return_onerror = true;
2318 key_dest = key_game;
2319 m_state = m_none;
2320 Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
2321 break;
2324 break;
2326 case K_BACKSPACE:
2327 if (lanConfig_cursor == 0)
2329 if (strlen(lanConfig_portname))
2330 lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
2333 if (lanConfig_cursor == 2)
2335 if (strlen(lanConfig_joinname))
2336 lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
2338 break;
2340 default:
2341 if (key < 32 || key > 127)
2342 break;
2344 if (lanConfig_cursor == 2)
2346 l = strlen(lanConfig_joinname);
2347 if (l < 21)
2349 lanConfig_joinname[l+1] = 0;
2350 lanConfig_joinname[l] = key;
2354 if (key < '0' || key > '9')
2355 break;
2356 if (lanConfig_cursor == 0)
2358 l = strlen(lanConfig_portname);
2359 if (l < 5)
2361 lanConfig_portname[l+1] = 0;
2362 lanConfig_portname[l] = key;
2367 if (StartingGame && lanConfig_cursor == 2)
2369 if (key == K_UPARROW)
2370 lanConfig_cursor = 1;
2371 else
2372 lanConfig_cursor = 0;
2375 l = Q_atoi(lanConfig_portname);
2376 if (l > 65535)
2377 l = lanConfig_port;
2378 else
2379 lanConfig_port = l;
2380 sprintf(lanConfig_portname, "%u", lanConfig_port);
2383 //=============================================================================
2384 /* GAME OPTIONS MENU */
2386 typedef struct
2388 char *name;
2389 char *description;
2390 } level_t;
2392 level_t levels[] =
2394 {"start", "Entrance"}, // 0
2396 {"e1m1", "Slipgate Complex"}, // 1
2397 {"e1m2", "Castle of the Damned"},
2398 {"e1m3", "The Necropolis"},
2399 {"e1m4", "The Grisly Grotto"},
2400 {"e1m5", "Gloom Keep"},
2401 {"e1m6", "The Door To Chthon"},
2402 {"e1m7", "The House of Chthon"},
2403 {"e1m8", "Ziggurat Vertigo"},
2405 {"e2m1", "The Installation"}, // 9
2406 {"e2m2", "Ogre Citadel"},
2407 {"e2m3", "Crypt of Decay"},
2408 {"e2m4", "The Ebon Fortress"},
2409 {"e2m5", "The Wizard's Manse"},
2410 {"e2m6", "The Dismal Oubliette"},
2411 {"e2m7", "Underearth"},
2413 {"e3m1", "Termination Central"}, // 16
2414 {"e3m2", "The Vaults of Zin"},
2415 {"e3m3", "The Tomb of Terror"},
2416 {"e3m4", "Satan's Dark Delight"},
2417 {"e3m5", "Wind Tunnels"},
2418 {"e3m6", "Chambers of Torment"},
2419 {"e3m7", "The Haunted Halls"},
2421 {"e4m1", "The Sewage System"}, // 23
2422 {"e4m2", "The Tower of Despair"},
2423 {"e4m3", "The Elder God Shrine"},
2424 {"e4m4", "The Palace of Hate"},
2425 {"e4m5", "Hell's Atrium"},
2426 {"e4m6", "The Pain Maze"},
2427 {"e4m7", "Azure Agony"},
2428 {"e4m8", "The Nameless City"},
2430 {"end", "Shub-Niggurath's Pit"}, // 31
2432 {"dm1", "Place of Two Deaths"}, // 32
2433 {"dm2", "Claustrophobopolis"},
2434 {"dm3", "The Abandoned Base"},
2435 {"dm4", "The Bad Place"},
2436 {"dm5", "The Cistern"},
2437 {"dm6", "The Dark Zone"}
2440 //MED 01/06/97 added hipnotic levels
2441 level_t hipnoticlevels[] =
2443 {"start", "Command HQ"}, // 0
2445 {"hip1m1", "The Pumping Station"}, // 1
2446 {"hip1m2", "Storage Facility"},
2447 {"hip1m3", "The Lost Mine"},
2448 {"hip1m4", "Research Facility"},
2449 {"hip1m5", "Military Complex"},
2451 {"hip2m1", "Ancient Realms"}, // 6
2452 {"hip2m2", "The Black Cathedral"},
2453 {"hip2m3", "The Catacombs"},
2454 {"hip2m4", "The Crypt"},
2455 {"hip2m5", "Mortum's Keep"},
2456 {"hip2m6", "The Gremlin's Domain"},
2458 {"hip3m1", "Tur Torment"}, // 12
2459 {"hip3m2", "Pandemonium"},
2460 {"hip3m3", "Limbo"},
2461 {"hip3m4", "The Gauntlet"},
2463 {"hipend", "Armagon's Lair"}, // 16
2465 {"hipdm1", "The Edge of Oblivion"} // 17
2468 //PGM 01/07/97 added rogue levels
2469 //PGM 03/02/97 added dmatch level
2470 level_t roguelevels[] =
2472 {"start", "Split Decision"},
2473 {"r1m1", "Deviant's Domain"},
2474 {"r1m2", "Dread Portal"},
2475 {"r1m3", "Judgement Call"},
2476 {"r1m4", "Cave of Death"},
2477 {"r1m5", "Towers of Wrath"},
2478 {"r1m6", "Temple of Pain"},
2479 {"r1m7", "Tomb of the Overlord"},
2480 {"r2m1", "Tempus Fugit"},
2481 {"r2m2", "Elemental Fury I"},
2482 {"r2m3", "Elemental Fury II"},
2483 {"r2m4", "Curse of Osiris"},
2484 {"r2m5", "Wizard's Keep"},
2485 {"r2m6", "Blood Sacrifice"},
2486 {"r2m7", "Last Bastion"},
2487 {"r2m8", "Source of Evil"},
2488 {"ctf1", "Division of Change"}
2491 typedef struct
2493 char *description;
2494 int firstLevel;
2495 int levels;
2496 } episode_t;
2498 episode_t episodes[] =
2500 {"Welcome to Quake", 0, 1},
2501 {"Doomed Dimension", 1, 8},
2502 {"Realm of Black Magic", 9, 7},
2503 {"Netherworld", 16, 7},
2504 {"The Elder World", 23, 8},
2505 {"Final Level", 31, 1},
2506 {"Deathmatch Arena", 32, 6}
2509 //MED 01/06/97 added hipnotic episodes
2510 episode_t hipnoticepisodes[] =
2512 {"Scourge of Armagon", 0, 1},
2513 {"Fortress of the Dead", 1, 5},
2514 {"Dominion of Darkness", 6, 6},
2515 {"The Rift", 12, 4},
2516 {"Final Level", 16, 1},
2517 {"Deathmatch Arena", 17, 1}
2520 //PGM 01/07/97 added rogue episodes
2521 //PGM 03/02/97 added dmatch episode
2522 episode_t rogueepisodes[] =
2524 {"Introduction", 0, 1},
2525 {"Hell's Fortress", 1, 7},
2526 {"Corridors of Time", 8, 8},
2527 {"Deathmatch Arena", 16, 1}
2530 int startepisode;
2531 int startlevel;
2532 int maxplayers;
2533 qboolean m_serverInfoMessage = false;
2534 double m_serverInfoMessageTime;
2536 void M_Menu_GameOptions_f (void)
2538 key_dest = key_menu;
2539 m_state = m_gameoptions;
2540 m_entersound = true;
2541 if (maxplayers == 0)
2542 maxplayers = svs.maxclients;
2543 if (maxplayers < 2)
2544 maxplayers = svs.maxclientslimit;
2548 int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
2549 #define NUM_GAMEOPTIONS 9
2550 int gameoptions_cursor;
2552 void M_GameOptions_Draw (void)
2554 qpic_t *p;
2555 int x;
2557 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2558 p = Draw_CachePic ("gfx/p_multi.lmp");
2559 M_DrawPic ( (320-p->width)/2, 4, p);
2561 M_DrawTextBox (152, 32, 10, 1);
2562 M_Print (160, 40, "begin game");
2564 M_Print (0, 56, " Max players");
2565 M_Print (160, 56, va("%i", maxplayers) );
2567 M_Print (0, 64, " Game Type");
2568 if (coop.value)
2569 M_Print (160, 64, "Cooperative");
2570 else
2571 M_Print (160, 64, "Deathmatch");
2573 M_Print (0, 72, " Teamplay");
2574 if (rogue)
2576 char *msg;
2578 switch((int)teamplay.value)
2580 case 1: msg = "No Friendly Fire"; break;
2581 case 2: msg = "Friendly Fire"; break;
2582 case 3: msg = "Tag"; break;
2583 case 4: msg = "Capture the Flag"; break;
2584 case 5: msg = "One Flag CTF"; break;
2585 case 6: msg = "Three Team CTF"; break;
2586 default: msg = "Off"; break;
2588 M_Print (160, 72, msg);
2590 else
2592 char *msg;
2594 switch((int)teamplay.value)
2596 case 1: msg = "No Friendly Fire"; break;
2597 case 2: msg = "Friendly Fire"; break;
2598 default: msg = "Off"; break;
2600 M_Print (160, 72, msg);
2603 M_Print (0, 80, " Skill");
2604 if (skill.value == 0)
2605 M_Print (160, 80, "Easy difficulty");
2606 else if (skill.value == 1)
2607 M_Print (160, 80, "Normal difficulty");
2608 else if (skill.value == 2)
2609 M_Print (160, 80, "Hard difficulty");
2610 else
2611 M_Print (160, 80, "Nightmare difficulty");
2613 M_Print (0, 88, " Frag Limit");
2614 if (fraglimit.value == 0)
2615 M_Print (160, 88, "none");
2616 else
2617 M_Print (160, 88, va("%i frags", (int)fraglimit.value));
2619 M_Print (0, 96, " Time Limit");
2620 if (timelimit.value == 0)
2621 M_Print (160, 96, "none");
2622 else
2623 M_Print (160, 96, va("%i minutes", (int)timelimit.value));
2625 M_Print (0, 112, " Episode");
2626 //MED 01/06/97 added hipnotic episodes
2627 if (hipnotic)
2628 M_Print (160, 112, hipnoticepisodes[startepisode].description);
2629 //PGM 01/07/97 added rogue episodes
2630 else if (rogue)
2631 M_Print (160, 112, rogueepisodes[startepisode].description);
2632 else
2633 M_Print (160, 112, episodes[startepisode].description);
2635 M_Print (0, 120, " Level");
2636 //MED 01/06/97 added hipnotic episodes
2637 if (hipnotic)
2639 M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
2640 M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
2642 //PGM 01/07/97 added rogue episodes
2643 else if (rogue)
2645 M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
2646 M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
2648 else
2650 M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
2651 M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
2654 // line cursor
2655 M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
2657 if (m_serverInfoMessage)
2659 if ((realtime - m_serverInfoMessageTime) < 5.0)
2661 x = (320-26*8)/2;
2662 M_DrawTextBox (x, 138, 24, 4);
2663 x += 8;
2664 M_Print (x, 146, " More than 4 players ");
2665 M_Print (x, 154, " requires using command ");
2666 M_Print (x, 162, "line parameters; please ");
2667 M_Print (x, 170, " see techinfo.txt. ");
2669 else
2671 m_serverInfoMessage = false;
2677 void M_NetStart_Change (int dir)
2679 int count;
2681 switch (gameoptions_cursor)
2683 case 1:
2684 maxplayers += dir;
2685 if (maxplayers > svs.maxclientslimit)
2687 maxplayers = svs.maxclientslimit;
2688 m_serverInfoMessage = true;
2689 m_serverInfoMessageTime = realtime;
2691 if (maxplayers < 2)
2692 maxplayers = 2;
2693 break;
2695 case 2:
2696 Cvar_SetValue ("coop", coop.value ? 0 : 1);
2697 break;
2699 case 3:
2700 if (rogue)
2701 count = 6;
2702 else
2703 count = 2;
2705 Cvar_SetValue ("teamplay", teamplay.value + dir);
2706 if (teamplay.value > count)
2707 Cvar_SetValue ("teamplay", 0);
2708 else if (teamplay.value < 0)
2709 Cvar_SetValue ("teamplay", count);
2710 break;
2712 case 4:
2713 Cvar_SetValue ("skill", skill.value + dir);
2714 if (skill.value > 3)
2715 Cvar_SetValue ("skill", 0);
2716 if (skill.value < 0)
2717 Cvar_SetValue ("skill", 3);
2718 break;
2720 case 5:
2721 Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
2722 if (fraglimit.value > 100)
2723 Cvar_SetValue ("fraglimit", 0);
2724 if (fraglimit.value < 0)
2725 Cvar_SetValue ("fraglimit", 100);
2726 break;
2728 case 6:
2729 Cvar_SetValue ("timelimit", timelimit.value + dir*5);
2730 if (timelimit.value > 60)
2731 Cvar_SetValue ("timelimit", 0);
2732 if (timelimit.value < 0)
2733 Cvar_SetValue ("timelimit", 60);
2734 break;
2736 case 7:
2737 startepisode += dir;
2738 //MED 01/06/97 added hipnotic count
2739 if (hipnotic)
2740 count = 6;
2741 //PGM 01/07/97 added rogue count
2742 //PGM 03/02/97 added 1 for dmatch episode
2743 else if (rogue)
2744 count = 4;
2745 else if (registered.value)
2746 count = 7;
2747 else
2748 count = 2;
2750 if (startepisode < 0)
2751 startepisode = count - 1;
2753 if (startepisode >= count)
2754 startepisode = 0;
2756 startlevel = 0;
2757 break;
2759 case 8:
2760 startlevel += dir;
2761 //MED 01/06/97 added hipnotic episodes
2762 if (hipnotic)
2763 count = hipnoticepisodes[startepisode].levels;
2764 //PGM 01/06/97 added hipnotic episodes
2765 else if (rogue)
2766 count = rogueepisodes[startepisode].levels;
2767 else
2768 count = episodes[startepisode].levels;
2770 if (startlevel < 0)
2771 startlevel = count - 1;
2773 if (startlevel >= count)
2774 startlevel = 0;
2775 break;
2779 void M_GameOptions_Key (int key)
2781 switch (key)
2783 case K_ESCAPE:
2784 M_Menu_Net_f ();
2785 break;
2787 case K_UPARROW:
2788 S_LocalSound ("misc/menu1.wav");
2789 gameoptions_cursor--;
2790 if (gameoptions_cursor < 0)
2791 gameoptions_cursor = NUM_GAMEOPTIONS-1;
2792 break;
2794 case K_DOWNARROW:
2795 S_LocalSound ("misc/menu1.wav");
2796 gameoptions_cursor++;
2797 if (gameoptions_cursor >= NUM_GAMEOPTIONS)
2798 gameoptions_cursor = 0;
2799 break;
2801 case K_LEFTARROW:
2802 if (gameoptions_cursor == 0)
2803 break;
2804 S_LocalSound ("misc/menu3.wav");
2805 M_NetStart_Change (-1);
2806 break;
2808 case K_RIGHTARROW:
2809 if (gameoptions_cursor == 0)
2810 break;
2811 S_LocalSound ("misc/menu3.wav");
2812 M_NetStart_Change (1);
2813 break;
2815 case K_ENTER:
2816 S_LocalSound ("misc/menu2.wav");
2817 if (gameoptions_cursor == 0)
2819 if (sv.active)
2820 Cbuf_AddText ("disconnect\n");
2821 Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined
2822 Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
2823 SCR_BeginLoadingPlaque ();
2825 if (hipnotic)
2826 Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
2827 else if (rogue)
2828 Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
2829 else
2830 Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
2832 return;
2835 M_NetStart_Change (1);
2836 break;
2840 //=============================================================================
2841 /* SEARCH MENU */
2843 qboolean searchComplete = false;
2844 double searchCompleteTime;
2846 void M_Menu_Search_f (void)
2848 key_dest = key_menu;
2849 m_state = m_search;
2850 m_entersound = false;
2851 slistSilent = true;
2852 slistLocal = false;
2853 searchComplete = false;
2854 NET_Slist_f();
2859 void M_Search_Draw (void)
2861 qpic_t *p;
2862 int x;
2864 p = Draw_CachePic ("gfx/p_multi.lmp");
2865 M_DrawPic ( (320-p->width)/2, 4, p);
2866 x = (320/2) - ((12*8)/2) + 4;
2867 M_DrawTextBox (x-8, 32, 12, 1);
2868 M_Print (x, 40, "Searching...");
2870 if(slistInProgress)
2872 NET_Poll();
2873 return;
2876 if (! searchComplete)
2878 searchComplete = true;
2879 searchCompleteTime = realtime;
2882 if (hostCacheCount)
2884 M_Menu_ServerList_f ();
2885 return;
2888 M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
2889 if ((realtime - searchCompleteTime) < 3.0)
2890 return;
2892 M_Menu_LanConfig_f ();
2896 void M_Search_Key (int key)
2900 //=============================================================================
2901 /* SLIST MENU */
2903 int slist_cursor;
2904 qboolean slist_sorted;
2906 void M_Menu_ServerList_f (void)
2908 key_dest = key_menu;
2909 m_state = m_slist;
2910 m_entersound = true;
2911 slist_cursor = 0;
2912 m_return_onerror = false;
2913 m_return_reason[0] = 0;
2914 slist_sorted = false;
2918 void M_ServerList_Draw (void)
2920 int n;
2921 char string [64];
2922 qpic_t *p;
2924 if (!slist_sorted)
2926 if (hostCacheCount > 1)
2928 int i,j;
2929 hostcache_t temp;
2930 for (i = 0; i < hostCacheCount; i++)
2931 for (j = i+1; j < hostCacheCount; j++)
2932 if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
2934 Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
2935 Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
2936 Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
2939 slist_sorted = true;
2942 p = Draw_CachePic ("gfx/p_multi.lmp");
2943 M_DrawPic ( (320-p->width)/2, 4, p);
2944 for (n = 0; n < hostCacheCount; n++)
2946 if (hostcache[n].maxusers)
2947 sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
2948 else
2949 sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
2950 M_Print (16, 32 + 8*n, string);
2952 M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
2954 if (*m_return_reason)
2955 M_PrintWhite (16, 148, m_return_reason);
2959 void M_ServerList_Key (int k)
2961 switch (k)
2963 case K_ESCAPE:
2964 M_Menu_LanConfig_f ();
2965 break;
2967 case K_SPACE:
2968 M_Menu_Search_f ();
2969 break;
2971 case K_UPARROW:
2972 case K_LEFTARROW:
2973 S_LocalSound ("misc/menu1.wav");
2974 slist_cursor--;
2975 if (slist_cursor < 0)
2976 slist_cursor = hostCacheCount - 1;
2977 break;
2979 case K_DOWNARROW:
2980 case K_RIGHTARROW:
2981 S_LocalSound ("misc/menu1.wav");
2982 slist_cursor++;
2983 if (slist_cursor >= hostCacheCount)
2984 slist_cursor = 0;
2985 break;
2987 case K_ENTER:
2988 S_LocalSound ("misc/menu2.wav");
2989 m_return_state = m_state;
2990 m_return_onerror = true;
2991 slist_sorted = false;
2992 key_dest = key_game;
2993 m_state = m_none;
2994 Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
2995 break;
2997 default:
2998 break;
3003 //=============================================================================
3004 /* Menu Subsystem */
3007 void M_Init (void)
3009 Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
3011 Cmd_AddCommand ("menu_main", M_Menu_Main_f);
3012 Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
3013 Cmd_AddCommand ("menu_load", M_Menu_Load_f);
3014 Cmd_AddCommand ("menu_save", M_Menu_Save_f);
3015 Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
3016 Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
3017 Cmd_AddCommand ("menu_options", M_Menu_Options_f);
3018 Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
3019 Cmd_AddCommand ("menu_video", M_Menu_Video_f);
3020 Cmd_AddCommand ("help", M_Menu_Help_f);
3021 Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
3025 void M_Draw (void)
3027 if (m_state == m_none || key_dest != key_menu)
3028 return;
3030 if (!m_recursiveDraw)
3032 scr_copyeverything = 1;
3034 if (scr_con_current)
3036 Draw_ConsoleBackground (vid.height);
3037 VID_UnlockBuffer ();
3038 S_ExtraUpdate ();
3039 VID_LockBuffer ();
3041 else
3042 Draw_FadeScreen ();
3044 scr_fullupdate = 0;
3046 else
3048 m_recursiveDraw = false;
3051 switch (m_state)
3053 case m_none:
3054 break;
3056 case m_main:
3057 M_Main_Draw ();
3058 break;
3060 case m_singleplayer:
3061 M_SinglePlayer_Draw ();
3062 break;
3064 case m_load:
3065 M_Load_Draw ();
3066 break;
3068 case m_save:
3069 M_Save_Draw ();
3070 break;
3072 case m_multiplayer:
3073 M_MultiPlayer_Draw ();
3074 break;
3076 case m_setup:
3077 M_Setup_Draw ();
3078 break;
3080 case m_net:
3081 M_Net_Draw ();
3082 break;
3084 case m_options:
3085 M_Options_Draw ();
3086 break;
3088 case m_keys:
3089 M_Keys_Draw ();
3090 break;
3092 case m_video:
3093 M_Video_Draw ();
3094 break;
3096 case m_help:
3097 M_Help_Draw ();
3098 break;
3100 case m_quit:
3101 M_Quit_Draw ();
3102 break;
3104 case m_serialconfig:
3105 M_SerialConfig_Draw ();
3106 break;
3108 case m_modemconfig:
3109 M_ModemConfig_Draw ();
3110 break;
3112 case m_lanconfig:
3113 M_LanConfig_Draw ();
3114 break;
3116 case m_gameoptions:
3117 M_GameOptions_Draw ();
3118 break;
3120 case m_search:
3121 M_Search_Draw ();
3122 break;
3124 case m_slist:
3125 M_ServerList_Draw ();
3126 break;
3129 if (m_entersound)
3131 S_LocalSound ("misc/menu2.wav");
3132 m_entersound = false;
3135 VID_UnlockBuffer ();
3136 S_ExtraUpdate ();
3137 VID_LockBuffer ();
3141 void M_Keydown (int key)
3143 switch (m_state)
3145 case m_none:
3146 return;
3148 case m_main:
3149 M_Main_Key (key);
3150 return;
3152 case m_singleplayer:
3153 M_SinglePlayer_Key (key);
3154 return;
3156 case m_load:
3157 M_Load_Key (key);
3158 return;
3160 case m_save:
3161 M_Save_Key (key);
3162 return;
3164 case m_multiplayer:
3165 M_MultiPlayer_Key (key);
3166 return;
3168 case m_setup:
3169 M_Setup_Key (key);
3170 return;
3172 case m_net:
3173 M_Net_Key (key);
3174 return;
3176 case m_options:
3177 M_Options_Key (key);
3178 return;
3180 case m_keys:
3181 M_Keys_Key (key);
3182 return;
3184 case m_video:
3185 M_Video_Key (key);
3186 return;
3188 case m_help:
3189 M_Help_Key (key);
3190 return;
3192 case m_quit:
3193 M_Quit_Key (key);
3194 return;
3196 case m_serialconfig:
3197 M_SerialConfig_Key (key);
3198 return;
3200 case m_modemconfig:
3201 M_ModemConfig_Key (key);
3202 return;
3204 case m_lanconfig:
3205 M_LanConfig_Key (key);
3206 return;
3208 case m_gameoptions:
3209 M_GameOptions_Key (key);
3210 return;
3212 case m_search:
3213 M_Search_Key (key);
3214 break;
3216 case m_slist:
3217 M_ServerList_Key (key);
3218 return;
3223 void M_ConfigureNetSubsystem(void)
3225 // enable/disable net systems to match desired config
3227 Cbuf_AddText ("stopdemo\n");
3228 if (SerialConfig || DirectConfig)
3230 Cbuf_AddText ("com1 enable\n");
3233 if (IPXConfig || TCPIPConfig)
3234 net_hostport = lanConfig_port;