1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20#include "quakedef.h"
21#include "winquake.h"
22
23void (*vid_menudrawfn)(void);
24void (*vid_menukeyfn)(int key);
25
26enum {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;
27
28void M_Menu_Main_f (void);
29	void M_Menu_SinglePlayer_f (void);
30		void M_Menu_Load_f (void);
31		void M_Menu_Save_f (void);
32	void M_Menu_MultiPlayer_f (void);
33		void M_Menu_Setup_f (void);
34		void M_Menu_Net_f (void);
35	void M_Menu_Options_f (void);
36		void M_Menu_Keys_f (void);
37		void M_Menu_Video_f (void);
38	void M_Menu_Help_f (void);
39	void M_Menu_Quit_f (void);
40void M_Menu_SerialConfig_f (void);
41	void M_Menu_ModemConfig_f (void);
42void M_Menu_LanConfig_f (void);
43void M_Menu_GameOptions_f (void);
44void M_Menu_Search_f (void);
45void M_Menu_ServerList_f (void);
46
47void M_Main_Draw (void);
48	void M_SinglePlayer_Draw (void);
49		void M_Load_Draw (void);
50		void M_Save_Draw (void);
51	void M_MultiPlayer_Draw (void);
52		void M_Setup_Draw (void);
53		void M_Net_Draw (void);
54	void M_Options_Draw (void);
55		void M_Keys_Draw (void);
56		void M_Video_Draw (void);
57	void M_Help_Draw (void);
58	void M_Quit_Draw (void);
59void M_SerialConfig_Draw (void);
60	void M_ModemConfig_Draw (void);
61void M_LanConfig_Draw (void);
62void M_GameOptions_Draw (void);
63void M_Search_Draw (void);
64void M_ServerList_Draw (void);
65
66void M_Main_Key (int key);
67	void M_SinglePlayer_Key (int key);
68		void M_Load_Key (int key);
69		void M_Save_Key (int key);
70	void M_MultiPlayer_Key (int key);
71		void M_Setup_Key (int key);
72		void M_Net_Key (int key);
73	void M_Options_Key (int key);
74		void M_Keys_Key (int key);
75		void M_Video_Key (int key);
76	void M_Help_Key (int key);
77	void M_Quit_Key (int key);
78void M_SerialConfig_Key (int key);
79	void M_ModemConfig_Key (int key);
80void M_LanConfig_Key (int key);
81void M_GameOptions_Key (int key);
82void M_Search_Key (int key);
83void M_ServerList_Key (int key);
84
85qboolean	m_entersound;		// play after drawing a frame, so caching
86								// won't disrupt the sound
87qboolean	m_recursiveDraw;
88
89int			m_return_state;
90qboolean	m_return_onerror;
91char		m_return_reason [32];
92
93#define StartingGame	(m_multiplayer_cursor == 1)
94#define JoiningGame		(m_multiplayer_cursor == 0)
95#define SerialConfig	(m_net_cursor == 0)
96#define DirectConfig	(m_net_cursor == 1)
97#define	IPXConfig		(m_net_cursor == 2)
98#define	TCPIPConfig		(m_net_cursor == 3)
99
100void M_ConfigureNetSubsystem(void);
101
102//=============================================================================
103/* Support Routines */
104
105/*
106================
107M_DrawCharacter
108
109Draws one solid graphics character
110================
111*/
112void M_DrawCharacter (int cx, int line, int num)
113{
114	Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
115}
116
117void M_Print (int cx, int cy, char *str)
118{
119	while (*str)
120	{
121		M_DrawCharacter (cx, cy, (*str)+128);
122		str++;
123		cx += 8;
124	}
125}
126
127void M_PrintWhite (int cx, int cy, char *str)
128{
129	while (*str)
130	{
131		M_DrawCharacter (cx, cy, *str);
132		str++;
133		cx += 8;
134	}
135}
136
137void M_DrawTransPic (int x, int y, qpic_t *pic)
138{
139	Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
140}
141
142void M_DrawPic (int x, int y, qpic_t *pic)
143{
144	Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
145}
146
147byte identityTable[256];
148byte translationTable[256];
149
150void M_BuildTranslationTable(int top, int bottom)
151{
152	int		j;
153	byte	*dest, *source;
154
155	for (j = 0; j < 256; j++)
156		identityTable[j] = j;
157	dest = translationTable;
158	source = identityTable;
159	memcpy (dest, source, 256);
160
161	if (top < 128)	// the artists made some backwards ranges.  sigh.
162		memcpy (dest + TOP_RANGE, source + top, 16);
163	else
164		for (j=0 ; j<16 ; j++)
165			dest[TOP_RANGE+j] = source[top+15-j];
166
167	if (bottom < 128)
168		memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
169	else
170		for (j=0 ; j<16 ; j++)
171			dest[BOTTOM_RANGE+j] = source[bottom+15-j];
172}
173
174
175void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
176{
177	Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
178}
179
180
181void M_DrawTextBox (int x, int y, int width, int lines)
182{
183	qpic_t	*p;
184	int		cx, cy;
185	int		n;
186
187	// draw left side
188	cx = x;
189	cy = y;
190	p = Draw_CachePic ("gfx/box_tl.lmp");
191	M_DrawTransPic (cx, cy, p);
192	p = Draw_CachePic ("gfx/box_ml.lmp");
193	for (n = 0; n < lines; n++)
194	{
195		cy += 8;
196		M_DrawTransPic (cx, cy, p);
197	}
198	p = Draw_CachePic ("gfx/box_bl.lmp");
199	M_DrawTransPic (cx, cy+8, p);
200
201	// draw middle
202	cx += 8;
203	while (width > 0)
204	{
205		cy = y;
206		p = Draw_CachePic ("gfx/box_tm.lmp");
207		M_DrawTransPic (cx, cy, p);
208		p = Draw_CachePic ("gfx/box_mm.lmp");
209		for (n = 0; n < lines; n++)
210		{
211			cy += 8;
212			if (n == 1)
213				p = Draw_CachePic ("gfx/box_mm2.lmp");
214			M_DrawTransPic (cx, cy, p);
215		}
216		p = Draw_CachePic ("gfx/box_bm.lmp");
217		M_DrawTransPic (cx, cy+8, p);
218		width -= 2;
219		cx += 16;
220	}
221
222	// draw right side
223	cy = y;
224	p = Draw_CachePic ("gfx/box_tr.lmp");
225	M_DrawTransPic (cx, cy, p);
226	p = Draw_CachePic ("gfx/box_mr.lmp");
227	for (n = 0; n < lines; n++)
228	{
229		cy += 8;
230		M_DrawTransPic (cx, cy, p);
231	}
232	p = Draw_CachePic ("gfx/box_br.lmp");
233	M_DrawTransPic (cx, cy+8, p);
234}
235
236//=============================================================================
237
238int m_save_demonum;
239
240/*
241================
242M_ToggleMenu_f
243================
244*/
245void M_ToggleMenu_f (void)
246{
247	m_entersound = true;
248
249	if (key_dest == key_menu)
250	{
251		if (m_state != m_main)
252		{
253			M_Menu_Main_f ();
254			return;
255		}
256		key_dest = key_game;
257		m_state = m_none;
258		return;
259	}
260	if (key_dest == key_console)
261	{
262		Con_ToggleConsole_f ();
263	}
264	else
265	{
266		M_Menu_Main_f ();
267	}
268}
269
270
271//=============================================================================
272/* MAIN MENU */
273
274int	m_main_cursor;
275#define	MAIN_ITEMS	5
276
277
278void M_Menu_Main_f (void)
279{
280	if (key_dest != key_menu)
281	{
282		m_save_demonum = cls.demonum;
283		cls.demonum = -1;
284	}
285	key_dest = key_menu;
286	m_state = m_main;
287	m_entersound = true;
288}
289
290
291void M_Main_Draw (void)
292{
293	int		f;
294	qpic_t	*p;
295
296	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
297	p = Draw_CachePic ("gfx/ttl_main.lmp");
298	M_DrawPic ( (320-p->width)/2, 4, p);
299	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
300
301	f = (int)(realtime * 10)%6;
302
303	M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
304}
305
306
307void M_Main_Key (int key)
308{
309	switch (key)
310	{
311	case K_ESCAPE:
312		key_dest = key_game;
313		m_state = m_none;
314		cls.demonum = m_save_demonum;
315		if (cls.demonum != -1 && !cls.demoplayback && cls.state == ca_disconnected)
316			CL_NextDemo ();
317		break;
318
319	case K_DOWNARROW:
320		S_LocalSound ("misc/menu1.wav");
321		if (++m_main_cursor >= MAIN_ITEMS)
322			m_main_cursor = 0;
323		break;
324
325	case K_UPARROW:
326		S_LocalSound ("misc/menu1.wav");
327		if (--m_main_cursor < 0)
328			m_main_cursor = MAIN_ITEMS - 1;
329		break;
330
331	case K_ENTER:
332		m_entersound = true;
333
334		switch (m_main_cursor)
335		{
336		case 0:
337			M_Menu_SinglePlayer_f ();
338			break;
339
340		case 1:
341			M_Menu_MultiPlayer_f ();
342			break;
343
344		case 2:
345			M_Menu_Options_f ();
346			break;
347
348		case 3:
349			M_Menu_Help_f ();
350			break;
351
352		case 4:
353			M_Menu_Quit_f ();
354			break;
355		}
356	}
357}
358
359
360//=============================================================================
361/* OPTIONS MENU */
362
363#define	OPTIONS_ITEMS	16
364
365#define	SLIDER_RANGE	10
366
367int		options_cursor;
368
369void M_Menu_Options_f (void)
370{
371	key_dest = key_menu;
372	m_state = m_options;
373	m_entersound = true;
374}
375
376
377void M_AdjustSliders (int dir)
378{
379	S_LocalSound ("misc/menu3.wav");
380
381	switch (options_cursor)
382	{
383	case 3:	// screen size
384		scr_viewsize.value += dir * 10;
385		if (scr_viewsize.value < 30)
386			scr_viewsize.value = 30;
387		if (scr_viewsize.value > 120)
388			scr_viewsize.value = 120;
389		Cvar_SetValue ("viewsize", scr_viewsize.value);
390		break;
391	case 4:	// gamma
392		v_gamma.value -= dir * 0.05;
393		if (v_gamma.value < 0.5)
394			v_gamma.value = 0.5;
395		if (v_gamma.value > 1)
396			v_gamma.value = 1;
397		Cvar_SetValue ("gamma", v_gamma.value);
398		break;
399	case 5:	// mouse speed
400		sensitivity.value += dir * 0.5;
401		if (sensitivity.value < 1)
402			sensitivity.value = 1;
403		if (sensitivity.value > 11)
404			sensitivity.value = 11;
405		Cvar_SetValue ("sensitivity", sensitivity.value);
406		break;
407	case 6:	// music volume
408#ifdef _WIN32
409		bgmvolume.value += dir * 1.0;
410#else
411		bgmvolume.value += dir * 0.1;
412#endif
413		if (bgmvolume.value < 0)
414			bgmvolume.value = 0;
415		if (bgmvolume.value > 1)
416			bgmvolume.value = 1;
417		Cvar_SetValue ("bgmvolume", bgmvolume.value);
418		break;
419	case 7:	// sfx volume
420		volume.value += dir * 0.1;
421		if (volume.value < 0)
422			volume.value = 0;
423		if (volume.value > 1)
424			volume.value = 1;
425		Cvar_SetValue ("volume", volume.value);
426		break;
427
428	case 8:	// allways run
429		if (cl_forwardspeed.value > 200)
430		{
431			Cvar_SetValue ("cl_forwardspeed", 200);
432			Cvar_SetValue ("cl_backspeed", 200);
433		}
434		else
435		{
436			Cvar_SetValue ("cl_forwardspeed", 400);
437			Cvar_SetValue ("cl_backspeed", 400);
438		}
439		break;
440
441	case 9:	// invert mouse
442		Cvar_SetValue ("m_pitch", -m_pitch.value);
443		break;
444
445	case 10:	// lookspring
446		Cvar_SetValue ("lookspring", !lookspring.value);
447		break;
448
449	case 11:	// lookstrafe
450		Cvar_SetValue ("lookstrafe", !lookstrafe.value);
451		break;
452
453	case 12:
454		Cvar_SetValue ("cl_sbar", !cl_sbar.value);
455		break;
456
457	case 13:
458		Cvar_SetValue ("cl_hudswap", !cl_hudswap.value);
459
460	case 15:	// _windowed_mouse
461		Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
462		break;
463	}
464}
465
466
467void M_DrawSlider (int x, int y, float range)
468{
469	int	i;
470
471	if (range < 0)
472		range = 0;
473	if (range > 1)
474		range = 1;
475	M_DrawCharacter (x-8, y, 128);
476	for (i=0 ; i<SLIDER_RANGE ; i++)
477		M_DrawCharacter (x + i*8, y, 129);
478	M_DrawCharacter (x+i*8, y, 130);
479	M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
480}
481
482void M_DrawCheckbox (int x, int y, int on)
483{
484#if 0
485	if (on)
486		M_DrawCharacter (x, y, 131);
487	else
488		M_DrawCharacter (x, y, 129);
489#endif
490	if (on)
491		M_Print (x, y, "on");
492	else
493		M_Print (x, y, "off");
494}
495
496void M_Options_Draw (void)
497{
498	float		r;
499	qpic_t	*p;
500
501	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
502	p = Draw_CachePic ("gfx/p_option.lmp");
503	M_DrawPic ( (320-p->width)/2, 4, p);
504
505	M_Print (16, 32, "    Customize controls");
506	M_Print (16, 40, "         Go to console");
507	M_Print (16, 48, "     Reset to defaults");
508
509	M_Print (16, 56, "           Screen size");
510	r = (scr_viewsize.value - 30) / (120 - 30);
511	M_DrawSlider (220, 56, r);
512
513	M_Print (16, 64, "            Brightness");
514	r = (1.0 - v_gamma.value) / 0.5;
515	M_DrawSlider (220, 64, r);
516
517	M_Print (16, 72, "           Mouse Speed");
518	r = (sensitivity.value - 1)/10;
519	M_DrawSlider (220, 72, r);
520
521	M_Print (16, 80, "       CD Music Volume");
522	r = bgmvolume.value;
523	M_DrawSlider (220, 80, r);
524
525	M_Print (16, 88, "          Sound Volume");
526	r = volume.value;
527	M_DrawSlider (220, 88, r);
528
529	M_Print (16, 96,  "            Always Run");
530	M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
531
532	M_Print (16, 104, "          Invert Mouse");
533	M_DrawCheckbox (220, 104, m_pitch.value < 0);
534
535	M_Print (16, 112, "            Lookspring");
536	M_DrawCheckbox (220, 112, lookspring.value);
537
538	M_Print (16, 120, "            Lookstrafe");
539	M_DrawCheckbox (220, 120, lookstrafe.value);
540
541	M_Print (16, 128, "    Use old status bar");
542	M_DrawCheckbox (220, 128, cl_sbar.value);
543
544	M_Print (16, 136, "      HUD on left side");
545	M_DrawCheckbox (220, 136, cl_hudswap.value);
546
547	if (vid_menudrawfn)
548		M_Print (16, 144, "         Video Options");
549
550#ifdef _WIN32
551	if (modestate == MS_WINDOWED)
552	{
553#endif
554		M_Print (16, 152, "             Use Mouse");
555		M_DrawCheckbox (220, 152, _windowed_mouse.value);
556#ifdef _WIN32
557	}
558#endif
559
560// cursor
561	M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
562}
563
564
565void M_Options_Key (int k)
566{
567	switch (k)
568	{
569	case K_ESCAPE:
570		M_Menu_Main_f ();
571		break;
572
573	case K_ENTER:
574		m_entersound = true;
575		switch (options_cursor)
576		{
577		case 0:
578			M_Menu_Keys_f ();
579			break;
580		case 1:
581			m_state = m_none;
582			Con_ToggleConsole_f ();
583			break;
584		case 2:
585			Cbuf_AddText ("exec default.cfg\n");
586			break;
587		case 14:
588			M_Menu_Video_f ();
589			break;
590		default:
591			M_AdjustSliders (1);
592			break;
593		}
594		return;
595
596	case K_UPARROW:
597		S_LocalSound ("misc/menu1.wav");
598		options_cursor--;
599		if (options_cursor < 0)
600			options_cursor = OPTIONS_ITEMS-1;
601		break;
602
603	case K_DOWNARROW:
604		S_LocalSound ("misc/menu1.wav");
605		options_cursor++;
606		if (options_cursor >= OPTIONS_ITEMS)
607			options_cursor = 0;
608		break;
609
610	case K_LEFTARROW:
611		M_AdjustSliders (-1);
612		break;
613
614	case K_RIGHTARROW:
615		M_AdjustSliders (1);
616		break;
617	}
618
619	if (options_cursor == 14 && vid_menudrawfn == NULL)
620	{
621		if (k == K_UPARROW)
622			options_cursor = 13;
623		else
624			options_cursor = 0;
625	}
626
627	if ((options_cursor == 15)
628#ifdef _WIN32
629	&& (modestate != MS_WINDOWED)
630#endif
631	)
632	{
633		if (k == K_UPARROW)
634			options_cursor = 14;
635		else
636			options_cursor = 0;
637	}
638}
639
640
641//=============================================================================
642/* KEYS MENU */
643
644char *bindnames[][2] =
645{
646{"+attack", 		"attack"},
647{"impulse 10", 		"change weapon"},
648{"+jump", 			"jump / swim up"},
649{"+forward", 		"walk forward"},
650{"+back", 			"backpedal"},
651{"+left", 			"turn left"},
652{"+right", 			"turn right"},
653{"+speed", 			"run"},
654{"+moveleft", 		"step left"},
655{"+moveright", 		"step right"},
656{"+strafe", 		"sidestep"},
657{"+lookup", 		"look up"},
658{"+lookdown", 		"look down"},
659{"centerview", 		"center view"},
660{"+mlook", 			"mouse look"},
661{"+klook", 			"keyboard look"},
662{"+moveup",			"swim up"},
663{"+movedown",		"swim down"}
664};
665
666#define	NUMCOMMANDS	(sizeof(bindnames)/sizeof(bindnames[0]))
667
668int		keys_cursor;
669int		bind_grab;
670
671void M_Menu_Keys_f (void)
672{
673	key_dest = key_menu;
674	m_state = m_keys;
675	m_entersound = true;
676}
677
678
679void M_FindKeysForCommand (char *command, int *twokeys)
680{
681	int		count;
682	int		j;
683	int		l;
684	char	*b;
685
686	twokeys[0] = twokeys[1] = -1;
687	l = strlen(command);
688	count = 0;
689
690	for (j=0 ; j<256 ; j++)
691	{
692		b = keybindings[j];
693		if (!b)
694			continue;
695		if (!strncmp (b, command, l) )
696		{
697			twokeys[count] = j;
698			count++;
699			if (count == 2)
700				break;
701		}
702	}
703}
704
705void M_UnbindCommand (char *command)
706{
707	int		j;
708	int		l;
709	char	*b;
710
711	l = strlen(command);
712
713	for (j=0 ; j<256 ; j++)
714	{
715		b = keybindings[j];
716		if (!b)
717			continue;
718		if (!strncmp (b, command, l) )
719			Key_SetBinding (j, "");
720	}
721}
722
723
724void M_Keys_Draw (void)
725{
726	int		i, l;
727	int		keys[2];
728	char	*name;
729	int		x, y;
730	qpic_t	*p;
731
732	p = Draw_CachePic ("gfx/ttl_cstm.lmp");
733	M_DrawPic ( (320-p->width)/2, 4, p);
734
735	if (bind_grab)
736		M_Print (12, 32, "Press a key or button for this action");
737	else
738		M_Print (18, 32, "Enter to change, backspace to clear");
739
740// search for known bindings
741	for (i=0 ; i< (int) NUMCOMMANDS ; i++)
742	{
743		y = 48 + 8*i;
744
745		M_Print (16, y, bindnames[i][1]);
746
747		l = strlen (bindnames[i][0]);
748
749		M_FindKeysForCommand (bindnames[i][0], keys);
750
751		if (keys[0] == -1)
752		{
753			M_Print (140, y, "???");
754		}
755		else
756		{
757			name = Key_KeynumToString (keys[0]);
758			M_Print (140, y, name);
759			x = strlen(name) * 8;
760			if (keys[1] != -1)
761			{
762				M_Print (140 + x + 8, y, "or");
763				M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
764			}
765		}
766	}
767
768	if (bind_grab)
769		M_DrawCharacter (130, 48 + keys_cursor*8, '=');
770	else
771		M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
772}
773
774
775void M_Keys_Key (int k)
776{
777	char	cmd[80];
778	int		keys[2];
779
780	if (bind_grab)
781	{	// defining a key
782		S_LocalSound ("misc/menu1.wav");
783		if (k == K_ESCAPE)
784		{
785			bind_grab = false;
786		}
787		else if (k != '`')
788		{
789			sprintf (cmd, "bind %s \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
790			Cbuf_InsertText (cmd);
791		}
792
793		bind_grab = false;
794		return;
795	}
796
797	switch (k)
798	{
799	case K_ESCAPE:
800		M_Menu_Options_f ();
801		break;
802
803	case K_LEFTARROW:
804	case K_UPARROW:
805		S_LocalSound ("misc/menu1.wav");
806		keys_cursor--;
807		if (keys_cursor < 0)
808			keys_cursor = NUMCOMMANDS-1;
809		break;
810
811	case K_DOWNARROW:
812	case K_RIGHTARROW:
813		S_LocalSound ("misc/menu1.wav");
814		keys_cursor++;
815		if (keys_cursor >= (int) NUMCOMMANDS)
816			keys_cursor = 0;
817		break;
818
819	case K_ENTER:		// go into bind mode
820		M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
821		S_LocalSound ("misc/menu2.wav");
822		if (keys[1] != -1)
823			M_UnbindCommand (bindnames[keys_cursor][0]);
824		bind_grab = true;
825		break;
826
827	case K_BACKSPACE:		// delete bindings
828	case K_DEL:				// delete bindings
829		S_LocalSound ("misc/menu2.wav");
830		M_UnbindCommand (bindnames[keys_cursor][0]);
831		break;
832	}
833}
834
835//=============================================================================
836/* VIDEO MENU */
837
838void M_Menu_Video_f (void)
839{
840	key_dest = key_menu;
841	m_state = m_video;
842	m_entersound = true;
843}
844
845
846void M_Video_Draw (void)
847{
848	(*vid_menudrawfn) ();
849}
850
851
852void M_Video_Key (int key)
853{
854	(*vid_menukeyfn) (key);
855}
856
857//=============================================================================
858/* HELP MENU */
859
860int		help_page;
861#define	NUM_HELP_PAGES	6
862
863
864void M_Menu_Help_f (void)
865{
866	key_dest = key_menu;
867	m_state = m_help;
868	m_entersound = true;
869	help_page = 0;
870}
871
872
873
874void M_Help_Draw (void)
875{
876	M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
877}
878
879
880void M_Help_Key (int key)
881{
882	switch (key)
883	{
884	case K_ESCAPE:
885		M_Menu_Main_f ();
886		break;
887
888	case K_UPARROW:
889	case K_RIGHTARROW:
890		m_entersound = true;
891		if (++help_page >= NUM_HELP_PAGES)
892			help_page = 0;
893		break;
894
895	case K_DOWNARROW:
896	case K_LEFTARROW:
897		m_entersound = true;
898		if (--help_page < 0)
899			help_page = NUM_HELP_PAGES-1;
900		break;
901	}
902
903}
904
905//=============================================================================
906/* QUIT MENU */
907
908int		msgNumber;
909int		m_quit_prevstate;
910qboolean	wasInMenus;
911
912char *quitMessage [] =
913{
914/* .........1.........2.... */
915  "  Are you gonna quit    ",
916  "  this game just like   ",
917  "   everything else?     ",
918  "                        ",
919
920  " Milord, methinks that  ",
921  "   thou art a lowly     ",
922  " quitter. Is this true? ",
923  "                        ",
924
925  " Do I need to bust your ",
926  "  face open for trying  ",
927  "        to quit?        ",
928  "                        ",
929
930  " Man, I oughta smack you",
931  "   for trying to quit!  ",
932  "     Press Y to get     ",
933  "      smacked out.      ",
934
935  " Press Y to quit like a ",
936  "   big loser in life.   ",
937  "  Press N to stay proud ",
938  "    and successful!     ",
939
940  "   If you press Y to    ",
941  "  quit, I will summon   ",
942  "  Satan all over your   ",
943  "      hard drive!       ",
944
945  "  Um, Asmodeus dislikes ",
946  " his children trying to ",
947  " quit. Press Y to return",
948  "   to your Tinkertoys.  ",
949
950  "  If you quit now, I'll ",
951  "  throw a blanket-party ",
952  "   for you next time!   ",
953  "                        "
954};
955
956void M_Menu_Quit_f (void)
957{
958	if (m_state == m_quit)
959		return;
960	wasInMenus = (key_dest == key_menu);
961	key_dest = key_menu;
962	m_quit_prevstate = m_state;
963	m_state = m_quit;
964	m_entersound = true;
965	msgNumber = rand()&7;
966}
967
968
969void M_Quit_Key (int key)
970{
971	switch (key)
972	{
973	case K_ESCAPE:
974	case 'n':
975	case 'N':
976		if (wasInMenus)
977		{
978			m_state = m_quit_prevstate;
979			m_entersound = true;
980		}
981		else
982		{
983			key_dest = key_game;
984			m_state = m_none;
985		}
986		break;
987
988	case 'Y':
989	case 'y':
990		key_dest = key_console;
991		CL_Disconnect ();
992		Sys_Quit ();
993		break;
994
995	default:
996		break;
997	}
998
999}
1000
1001void M_Menu_SinglePlayer_f (void) {
1002	m_state = m_singleplayer;
1003}
1004
1005void M_SinglePlayer_Draw (void) {
1006	qpic_t	*p;
1007
1008	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1009//	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1010	p = Draw_CachePic ("gfx/ttl_sgl.lmp");
1011	M_DrawPic ( (320-p->width)/2, 4, p);
1012//	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
1013
1014	M_DrawTextBox (60, 10*8, 23, 4);
1015	M_PrintWhite (92, 12*8, "QuakeWorld is for");
1016	M_PrintWhite (88, 13*8, "Internet play only");
1017
1018}
1019
1020void M_SinglePlayer_Key (int key) {
1021	if (key == K_ESCAPE || key==K_ENTER)
1022		m_state = m_main;
1023}
1024
1025void M_Menu_MultiPlayer_f (void) {
1026	m_state = m_multiplayer;
1027}
1028
1029void M_MultiPlayer_Draw (void) {
1030	qpic_t	*p;
1031
1032	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1033//	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1034	p = Draw_CachePic ("gfx/p_multi.lmp");
1035	M_DrawPic ( (320-p->width)/2, 4, p);
1036//	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
1037
1038	M_DrawTextBox (46, 8*8, 27, 9);
1039	M_PrintWhite (72, 10*8, "If you want to find QW  ");
1040	M_PrintWhite (72, 11*8, "games, head on over to: ");
1041	     M_Print (72, 12*8, "   www.quakeworld.net   ");
1042	M_PrintWhite (72, 13*8, "          or            ");
1043	     M_Print (72, 14*8, "   www.quakespy.com     ");
1044	M_PrintWhite (72, 15*8, "For pointers on getting ");
1045	M_PrintWhite (72, 16*8, "        started!        ");
1046}
1047
1048void M_MultiPlayer_Key (int key) {
1049	if (key == K_ESCAPE || key==K_ENTER)
1050		m_state = m_main;
1051}
1052
1053void M_Quit_Draw (void)
1054{
1055#define VSTR(x) #x
1056#define VSTR2(x) VSTR(x)
1057	char *cmsg[] = {
1058//    0123456789012345678901234567890123456789
1059	"0            QuakeWorld",
1060	"1    version " VSTR2(VERSION) " by id Software",
1061	"0Programming",
1062	"1 John Carmack    Michael Abrash",
1063	"1 John Cash       Christian Antkow",
1064	"0Additional Programming",
1065	"1 Dave 'Zoid' Kirsch",
1066	"1 Jack 'morbid' Mathews",
1067	"0Id Software is not responsible for",
1068    "0providing technical support for",
1069	"0QUAKEWORLD(tm). (c)1996 Id Software,",
1070	"0Inc.  All Rights Reserved.",
1071	"0QUAKEWORLD(tm) is a trademark of Id",
1072	"0Software, Inc.",
1073	"1NOTICE: THE COPYRIGHT AND TRADEMARK",
1074	"1NOTICES APPEARING  IN YOUR COPY OF",
1075	"1QUAKE(r) ARE NOT MODIFIED BY THE USE",
1076	"1OF QUAKEWORLD(tm) AND REMAIN IN FULL",
1077	"1FORCE.",
1078	"0NIN(r) is a registered trademark",
1079	"0licensed to Nothing Interactive, Inc.",
1080	"0All rights reserved. Press y to exit",
1081	NULL };
1082	char **p;
1083	int y;
1084
1085	if (wasInMenus)
1086	{
1087		m_state = m_quit_prevstate;
1088		m_recursiveDraw = true;
1089		M_Draw ();
1090		m_state = m_quit;
1091	}
1092#if 1
1093	M_DrawTextBox (0, 0, 38, 23);
1094	y = 12;
1095	for (p = cmsg; *p; p++, y += 8) {
1096		if (**p == '0')
1097			M_PrintWhite (16, y, *p + 1);
1098		else
1099			M_Print (16, y,	*p + 1);
1100	}
1101#else
1102	M_DrawTextBox (56, 76, 24, 4);
1103	M_Print (64, 84,  quitMessage[msgNumber*4+0]);
1104	M_Print (64, 92,  quitMessage[msgNumber*4+1]);
1105	M_Print (64, 100, quitMessage[msgNumber*4+2]);
1106	M_Print (64, 108, quitMessage[msgNumber*4+3]);
1107#endif
1108}
1109
1110
1111
1112//=============================================================================
1113/* Menu Subsystem */
1114
1115
1116void M_Init (void)
1117{
1118	Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
1119
1120	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
1121	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
1122	Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
1123	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
1124	Cmd_AddCommand ("help", M_Menu_Help_f);
1125	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
1126}
1127
1128
1129void M_Draw (void)
1130{
1131	if (m_state == m_none || key_dest != key_menu)
1132		return;
1133
1134	if (!m_recursiveDraw)
1135	{
1136		scr_copyeverything = 1;
1137
1138		if (scr_con_current)
1139		{
1140			Draw_ConsoleBackground (vid.height);
1141			VID_UnlockBuffer ();
1142			S_ExtraUpdate ();
1143			VID_LockBuffer ();
1144		}
1145		else
1146			Draw_FadeScreen ();
1147
1148		scr_fullupdate = 0;
1149	}
1150	else
1151	{
1152		m_recursiveDraw = false;
1153	}
1154
1155	switch (m_state)
1156	{
1157	case m_none:
1158		break;
1159
1160	case m_main:
1161		M_Main_Draw ();
1162		break;
1163
1164	case m_singleplayer:
1165		M_SinglePlayer_Draw ();
1166		break;
1167
1168	case m_load:
1169//		M_Load_Draw ();
1170		break;
1171
1172	case m_save:
1173//		M_Save_Draw ();
1174		break;
1175
1176	case m_multiplayer:
1177		M_MultiPlayer_Draw ();
1178		break;
1179
1180	case m_setup:
1181//		M_Setup_Draw ();
1182		break;
1183
1184	case m_net:
1185//		M_Net_Draw ();
1186		break;
1187
1188	case m_options:
1189		M_Options_Draw ();
1190		break;
1191
1192	case m_keys:
1193		M_Keys_Draw ();
1194		break;
1195
1196	case m_video:
1197		M_Video_Draw ();
1198		break;
1199
1200	case m_help:
1201		M_Help_Draw ();
1202		break;
1203
1204	case m_quit:
1205		M_Quit_Draw ();
1206		break;
1207
1208	case m_serialconfig:
1209//		M_SerialConfig_Draw ();
1210		break;
1211
1212	case m_modemconfig:
1213//		M_ModemConfig_Draw ();
1214		break;
1215
1216	case m_lanconfig:
1217//		M_LanConfig_Draw ();
1218		break;
1219
1220	case m_gameoptions:
1221//		M_GameOptions_Draw ();
1222		break;
1223
1224	case m_search:
1225//		M_Search_Draw ();
1226		break;
1227
1228	case m_slist:
1229//		M_ServerList_Draw ();
1230		break;
1231	}
1232
1233	if (m_entersound)
1234	{
1235		S_LocalSound ("misc/menu2.wav");
1236		m_entersound = false;
1237	}
1238
1239	VID_UnlockBuffer ();
1240	S_ExtraUpdate ();
1241	VID_LockBuffer ();
1242}
1243
1244
1245void M_Keydown (int key)
1246{
1247	switch (m_state)
1248	{
1249	case m_none:
1250		return;
1251
1252	case m_main:
1253		M_Main_Key (key);
1254		return;
1255
1256	case m_singleplayer:
1257		M_SinglePlayer_Key (key);
1258		return;
1259
1260	case m_load:
1261//		M_Load_Key (key);
1262		return;
1263
1264	case m_save:
1265//		M_Save_Key (key);
1266		return;
1267
1268	case m_multiplayer:
1269		M_MultiPlayer_Key (key);
1270		return;
1271
1272	case m_setup:
1273//		M_Setup_Key (key);
1274		return;
1275
1276	case m_net:
1277//		M_Net_Key (key);
1278		return;
1279
1280	case m_options:
1281		M_Options_Key (key);
1282		return;
1283
1284	case m_keys:
1285		M_Keys_Key (key);
1286		return;
1287
1288	case m_video:
1289		M_Video_Key (key);
1290		return;
1291
1292	case m_help:
1293		M_Help_Key (key);
1294		return;
1295
1296	case m_quit:
1297		M_Quit_Key (key);
1298		return;
1299
1300	case m_serialconfig:
1301//		M_SerialConfig_Key (key);
1302		return;
1303
1304	case m_modemconfig:
1305//		M_ModemConfig_Key (key);
1306		return;
1307
1308	case m_lanconfig:
1309//		M_LanConfig_Key (key);
1310		return;
1311
1312	case m_gameoptions:
1313//		M_GameOptions_Key (key);
1314		return;
1315
1316	case m_search:
1317//		M_Search_Key (key);
1318		break;
1319
1320	case m_slist:
1321//		M_ServerList_Key (key);
1322		return;
1323	}
1324}
1325
1326
1327