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