1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #include <ctype.h>
21 #ifdef _WIN32
22 #include <io.h>
23 #endif
24 #include "client.h"
25 #include "../client/qmenu.h"
26 
27 static int	m_main_cursor;
28 
29 #define NUM_CURSOR_FRAMES 15
30 
31 static char *menu_in_sound		= "misc/menu1.wav";
32 static char *menu_move_sound	= "misc/menu2.wav";
33 static char *menu_out_sound		= "misc/menu3.wav";
34 
35 void M_Menu_Main_f (void);
36 static 	void M_Menu_Game_f (void);
37 static 		void M_Menu_LoadGame_f (void);
38 static 		void M_Menu_SaveGame_f (void);
39 static 		void M_Menu_PlayerConfig_f (void);
40 static 			void M_Menu_DownloadOptions_f (void);
41 static 		void M_Menu_Credits_f( void );
42 static 	void M_Menu_Multiplayer_f( void );
43 static 		void M_Menu_JoinServer_f (void);
44 static 			void M_Menu_AddressBook_f( void );
45 static 		void M_Menu_StartServer_f (void);
46 static 			void M_Menu_DMOptions_f (void);
47 static 	void M_Menu_Video_f (void);
48 static 	void M_Menu_Options_f (void);
49 static 		void M_Menu_R1Q2_f (void);
50 static 		void M_Menu_Keys_f (void);
51 static 	void M_Menu_Quit_f (void);
52 
53 qboolean	m_entersound;		// play after drawing a frame, so caching
54 								// won't disrupt the sound
55 
56 void	(*m_drawfunc) (void);
57 const char *(*m_keyfunc) (int key);
58 
59 //=============================================================================
60 /* Support Routines */
61 
62 #define	MAX_MENU_DEPTH	8
63 
ClampCvar(float min,float max,float value)64 static float ClampCvar( float min, float max, float value )
65 {
66 	if ( value < min ) return min;
67 	if ( value > max ) return max;
68 	return value;
69 }
70 
71 typedef struct
72 {
73 	void	(*draw) (void);
74 	const char *(*key) (int k);
75 } menulayer_t;
76 
77 menulayer_t	m_layers[MAX_MENU_DEPTH];
78 int		m_menudepth;
79 
M_Banner(char * name)80 static void M_Banner( char *name )
81 {
82 	int w, h;
83 
84 	re.DrawGetPicSize (&w, &h, name );
85 	re.DrawPic( viddef.width / 2 - w / 2, viddef.height / 2 - 110, name );
86 }
87 
M_PushMenu(void (* draw)(void),const char * (* key)(int k))88 static void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
89 {
90 	int		i;
91 
92 	/*if (Cvar_VariableValue ("maxclients") == 1
93 		&& Com_ServerState ())
94 		Cvar_Set ("paused", "1");*/
95 
96 	// if this menu is already present, drop back to that level
97 	// to avoid stacking menus by hotkeys
98 	for (i=0 ; i<m_menudepth ; i++)
99 		if (m_layers[i].draw == draw &&
100 			m_layers[i].key == key)
101 		{
102 			m_menudepth = i;
103 		}
104 
105 	if (i == m_menudepth)
106 	{
107 		if (m_menudepth >= MAX_MENU_DEPTH)
108 			Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
109 		m_layers[m_menudepth].draw = m_drawfunc;
110 		m_layers[m_menudepth].key = m_keyfunc;
111 		m_menudepth++;
112 	}
113 
114 	m_drawfunc = draw;
115 	m_keyfunc = key;
116 
117 	m_entersound = true;
118 
119 	cls.key_dest = key_menu;
120 }
121 
M_ForceMenuOff(void)122 void M_ForceMenuOff (void)
123 {
124 	m_drawfunc = 0;
125 	m_keyfunc = 0;
126 	cls.key_dest = key_game;
127 	m_menudepth = 0;
128 	Key_ClearStates ();
129 	//Cvar_Set ("paused", "0");
130 }
131 
M_PopMenu(void)132 void M_PopMenu (void)
133 {
134 	S_StartLocalSound( menu_out_sound );
135 	if (m_menudepth < 1)
136 		Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
137 	m_menudepth--;
138 
139 	m_drawfunc = m_layers[m_menudepth].draw;
140 	m_keyfunc = m_layers[m_menudepth].key;
141 
142 	if (!m_menudepth)
143 		M_ForceMenuOff ();
144 }
145 
146 
Default_MenuKey(menuframework_s * m,int key)147 static const char *Default_MenuKey( menuframework_s *m, int key )
148 {
149 	const char *sound = NULL;
150 	menucommon_s *item;
151 
152 	if ( m )
153 	{
154 		if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
155 		{
156 			if ( item->type == MTYPE_FIELD )
157 			{
158 				if ( Field_Key( ( menufield_s * ) item, key ) )
159 					return NULL;
160 			}
161 		}
162 	}
163 
164 	switch ( key )
165 	{
166 	case K_ESCAPE:
167 		M_PopMenu();
168 		return menu_out_sound;
169 	case K_KP_UPARROW:
170 	case K_UPARROW:
171 		if ( m )
172 		{
173 			m->cursor--;
174 			Menu_AdjustCursor( m, -1 );
175 			sound = menu_move_sound;
176 		}
177 		break;
178 	case K_TAB:
179 		if ( m )
180 		{
181 			m->cursor++;
182 			Menu_AdjustCursor( m, 1 );
183 			sound = menu_move_sound;
184 		}
185 		break;
186 	case K_KP_DOWNARROW:
187 	case K_DOWNARROW:
188 		if ( m )
189 		{
190 			m->cursor++;
191 			Menu_AdjustCursor( m, 1 );
192 			sound = menu_move_sound;
193 		}
194 		break;
195 	case K_KP_LEFTARROW:
196 	case K_LEFTARROW:
197 		if ( m )
198 		{
199 			Menu_SlideItem( m, -1 );
200 			sound = menu_move_sound;
201 		}
202 		break;
203 	case K_KP_RIGHTARROW:
204 	case K_RIGHTARROW:
205 		if ( m )
206 		{
207 			Menu_SlideItem( m, 1 );
208 			sound = menu_move_sound;
209 		}
210 		break;
211 
212 	case K_MOUSE1:
213 	case K_MOUSE2:
214 	case K_MOUSE3:
215 	case K_JOY1:
216 	case K_JOY2:
217 	case K_JOY3:
218 	case K_JOY4:
219 	case K_AUX1:
220 	case K_AUX2:
221 	case K_AUX3:
222 	case K_AUX4:
223 	case K_AUX5:
224 	case K_AUX6:
225 	case K_AUX7:
226 	case K_AUX8:
227 	case K_AUX9:
228 	case K_AUX10:
229 	case K_AUX11:
230 	case K_AUX12:
231 	case K_AUX13:
232 	case K_AUX14:
233 	case K_AUX15:
234 	case K_AUX16:
235 	case K_AUX17:
236 	case K_AUX18:
237 	case K_AUX19:
238 	case K_AUX20:
239 	case K_AUX21:
240 	case K_AUX22:
241 	case K_AUX23:
242 	case K_AUX24:
243 	case K_AUX25:
244 	case K_AUX26:
245 	case K_AUX27:
246 	case K_AUX28:
247 	case K_AUX29:
248 	case K_AUX30:
249 	case K_AUX31:
250 	case K_AUX32:
251 
252 	case K_KP_ENTER:
253 	case K_ENTER:
254 		if ( m )
255 			Menu_SelectItem( m );
256 		sound = menu_move_sound;
257 		break;
258 	}
259 
260 	return sound;
261 }
262 
263 //=============================================================================
264 
265 /*
266 ================
267 M_DrawCharacter
268 
269 Draws one solid graphics character
270 cx and cy are in 320*240 coordinates, and will be centered on
271 higher res screens.
272 ================
273 */
M_DrawCharacter(int cx,int cy,int num)274 static void M_DrawCharacter (int cx, int cy, int num)
275 {
276 	re.DrawChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1), num);
277 }
278 
M_Print(int cx,int cy,char * str)279 static void M_Print (int cx, int cy, char *str)
280 {
281 	while (*str)
282 	{
283 		M_DrawCharacter (cx, cy, (*str)+128);
284 		str++;
285 		cx += 8;
286 	}
287 }
288 
289 /*static void M_PrintWhite (int cx, int cy, char *str)
290 {
291 	while (*str)
292 	{
293 		M_DrawCharacter (cx, cy, *str);
294 		str++;
295 		cx += 8;
296 	}
297 }*/
298 
299 /*static void M_DrawPic (int x, int y, char *pic)
300 {
301 	re.DrawPic (x + ((viddef.width - 320)>>1), y + ((viddef.height - 240)>>1), pic);
302 }*/
303 
304 
305 /*
306 =============
307 M_DrawCursor
308 
309 Draws an animating cursor with the point at
310 x,y.  The pic will extend to the left of x,
311 and both above and below y.
312 =============
313 */
M_DrawCursor(int x,int y,int f)314 static void M_DrawCursor( int x, int y, int f )
315 {
316 	char	cursorname[80];
317 	static qboolean cached;
318 
319 	if ( !cached )
320 	{
321 		int i;
322 
323 		for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
324 		{
325 			Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
326 
327 			re.RegisterPic( cursorname );
328 		}
329 		cached = true;
330 	}
331 
332 	Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
333 	re.DrawPic( x, y, cursorname );
334 }
335 
M_DrawTextBox(int x,int y,int width,int lines)336 static void M_DrawTextBox (int x, int y, int width, int lines)
337 {
338 	int		cx, cy;
339 	int		n;
340 
341 	// draw left side
342 	cx = x;
343 	cy = y;
344 	M_DrawCharacter (cx, cy, 1);
345 	for (n = 0; n < lines; n++)
346 	{
347 		cy += 8;
348 		M_DrawCharacter (cx, cy, 4);
349 	}
350 	M_DrawCharacter (cx, cy+8, 7);
351 
352 	// draw middle
353 	cx += 8;
354 	while (width > 0)
355 	{
356 		cy = y;
357 		M_DrawCharacter (cx, cy, 2);
358 		for (n = 0; n < lines; n++)
359 		{
360 			cy += 8;
361 			M_DrawCharacter (cx, cy, 5);
362 		}
363 		M_DrawCharacter (cx, cy+8, 8);
364 		width -= 1;
365 		cx += 8;
366 	}
367 
368 	// draw right side
369 	cy = y;
370 	M_DrawCharacter (cx, cy, 3);
371 	for (n = 0; n < lines; n++)
372 	{
373 		cy += 8;
374 		M_DrawCharacter (cx, cy, 6);
375 	}
376 	M_DrawCharacter (cx, cy+8, 9);
377 }
378 
379 
380 /*
381 =======================================================================
382 
383 MAIN MENU
384 
385 =======================================================================
386 */
387 #define	MAIN_ITEMS	5
388 
389 
M_Main_Draw(void)390 static void M_Main_Draw (void)
391 {
392 	int i;
393 	int w, h;
394 	int ystart;
395 	int	xoffset;
396 	int widest = -1;
397 	int totalheight = 0;
398 	char litname[80];
399 	char *names[] =
400 	{
401 		"m_main_game",
402 		"m_main_multiplayer",
403 		"m_main_options",
404 		"m_main_video",
405 		"m_main_quit",
406 		0
407 	};
408 
409 	for ( i = 0; names[i] != 0; i++ )
410 	{
411 		re.DrawGetPicSize( &w, &h, names[i] );
412 
413 		if ( w > widest )
414 			widest = w;
415 		totalheight += ( h + 12 );
416 	}
417 
418 	ystart = ( viddef.height / 2 - 110 );
419 	xoffset = ( viddef.width - widest + 70 ) / 2;
420 
421 	for ( i = 0; names[i] != 0; i++ )
422 	{
423 		if ( i != m_main_cursor )
424 			re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
425 	}
426 	strcpy( litname, names[m_main_cursor] );
427 	strcat( litname, "_sel" );
428 	re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
429 
430 	M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
431 
432 	re.DrawGetPicSize( &w, &h, "m_main_plaque" );
433 	re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
434 
435 	re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
436 }
437 
438 
M_Main_Key(int key)439 static const char *M_Main_Key (int key)
440 {
441 	const char *sound = menu_move_sound;
442 
443 	switch (key)
444 	{
445 	case K_ESCAPE:
446 		M_PopMenu ();
447 		break;
448 
449 	case K_KP_DOWNARROW:
450 	case K_DOWNARROW:
451 		if (++m_main_cursor >= MAIN_ITEMS)
452 			m_main_cursor = 0;
453 		return sound;
454 
455 	case K_KP_UPARROW:
456 	case K_UPARROW:
457 		if (--m_main_cursor < 0)
458 			m_main_cursor = MAIN_ITEMS - 1;
459 		return sound;
460 
461 	case K_KP_ENTER:
462 	case K_ENTER:
463 		m_entersound = true;
464 
465 		switch (m_main_cursor)
466 		{
467 		case 0:
468 			M_Menu_Game_f ();
469 			break;
470 
471 		case 1:
472 			M_Menu_Multiplayer_f();
473 			break;
474 
475 		case 2:
476 			M_Menu_Options_f ();
477 			break;
478 
479 		case 3:
480 			M_Menu_Video_f ();
481 			break;
482 
483 		case 4:
484 			M_Menu_Quit_f ();
485 			break;
486 		}
487 	}
488 
489 	return NULL;
490 }
491 
492 
M_Menu_Main_f(void)493 void M_Menu_Main_f (void)
494 {
495 	M_PushMenu (M_Main_Draw, M_Main_Key);
496 }
497 
498 /*
499 =======================================================================
500 
501 MULTIPLAYER MENU
502 
503 =======================================================================
504 */
505 static menuframework_s	s_multiplayer_menu;
506 static menuaction_s		s_join_network_server_action;
507 static menuaction_s		s_start_network_server_action;
508 static menuaction_s		s_player_setup_action;
509 
Multiplayer_MenuDraw(void)510 static void Multiplayer_MenuDraw (void)
511 {
512 	M_Banner( "m_banner_multiplayer" );
513 
514 	Menu_AdjustCursor( &s_multiplayer_menu, 1 );
515 	Menu_Draw( &s_multiplayer_menu );
516 }
517 
PlayerSetupFunc(void * unused)518 static void PlayerSetupFunc( void *unused )
519 {
520 	M_Menu_PlayerConfig_f();
521 }
522 
JoinNetworkServerFunc(void * unused)523 static void JoinNetworkServerFunc( void *unused )
524 {
525 	M_Menu_JoinServer_f();
526 }
527 
StartNetworkServerFunc(void * unused)528 static void StartNetworkServerFunc( void *unused )
529 {
530 	M_Menu_StartServer_f ();
531 }
532 
Multiplayer_MenuInit(void)533 static void Multiplayer_MenuInit( void )
534 {
535 	s_multiplayer_menu.x = (int)(viddef.width * 0.50f) - 64;
536 	s_multiplayer_menu.nitems = 0;
537 
538 	s_join_network_server_action.generic.type	= MTYPE_ACTION;
539 	s_join_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
540 	s_join_network_server_action.generic.x		= 0;
541 	s_join_network_server_action.generic.y		= 0;
542 	s_join_network_server_action.generic.name	= " join network server";
543 	s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
544 
545 	s_start_network_server_action.generic.type	= MTYPE_ACTION;
546 	s_start_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
547 	s_start_network_server_action.generic.x		= 0;
548 	s_start_network_server_action.generic.y		= 10;
549 	s_start_network_server_action.generic.name	= " start network server";
550 	s_start_network_server_action.generic.callback = StartNetworkServerFunc;
551 
552 	s_player_setup_action.generic.type	= MTYPE_ACTION;
553 	s_player_setup_action.generic.flags  = QMF_LEFT_JUSTIFY;
554 	s_player_setup_action.generic.x		= 0;
555 	s_player_setup_action.generic.y		= 20;
556 	s_player_setup_action.generic.name	= " player setup";
557 	s_player_setup_action.generic.callback = PlayerSetupFunc;
558 
559 	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
560 	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
561 	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
562 
563 	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
564 
565 	Menu_Center( &s_multiplayer_menu );
566 }
567 
Multiplayer_MenuKey(int key)568 static const char *Multiplayer_MenuKey( int key )
569 {
570 	return Default_MenuKey( &s_multiplayer_menu, key );
571 }
572 
M_Menu_Multiplayer_f(void)573 static void M_Menu_Multiplayer_f( void )
574 {
575 	Multiplayer_MenuInit();
576 	M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
577 }
578 
579 /*
580 =======================================================================
581 
582 KEYS MENU
583 
584 =======================================================================
585 */
586 char *bindnames[][2] =
587 {
588 {"+attack", 		"attack"},
589 {"weapnext", 		"next weapon"},
590 {"weapprev", 		"previous weapon"},
591 {"+forward", 		"walk forward"},
592 {"+back", 			"backpedal"},
593 {"+left", 			"turn left"},
594 {"+right", 			"turn right"},
595 {"+speed", 			"run"},
596 {"+moveleft", 		"step left"},
597 {"+moveright", 		"step right"},
598 {"+strafe", 		"sidestep"},
599 {"+lookup", 		"look up"},
600 {"+lookdown", 		"look down"},
601 {"centerview", 		"center view"},
602 {"+mlook", 			"mouse look"},
603 {"+klook", 			"keyboard look"},
604 {"+moveup",			"up / jump"},
605 {"+movedown",		"down / crouch"},
606 
607 {"inven",			"inventory"},
608 {"invuse",			"use item"},
609 {"invdrop",			"drop item"},
610 {"invprev",			"prev item"},
611 {"invnext",			"next item"},
612 
613 {"cmd help", 		"help computer" },
614 { 0, 0 }
615 };
616 
617 int				keys_cursor;
618 static int		bind_grab;
619 
620 static menuframework_s	s_keys_menu;
621 static menuaction_s		s_keys_attack_action;
622 static menuaction_s		s_keys_change_weapon_action;
623 static menuaction_s		s_keys_walk_forward_action;
624 static menuaction_s		s_keys_backpedal_action;
625 static menuaction_s		s_keys_turn_left_action;
626 static menuaction_s		s_keys_turn_right_action;
627 static menuaction_s		s_keys_run_action;
628 static menuaction_s		s_keys_step_left_action;
629 static menuaction_s		s_keys_step_right_action;
630 static menuaction_s		s_keys_sidestep_action;
631 static menuaction_s		s_keys_look_up_action;
632 static menuaction_s		s_keys_look_down_action;
633 static menuaction_s		s_keys_center_view_action;
634 static menuaction_s		s_keys_mouse_look_action;
635 static menuaction_s		s_keys_keyboard_look_action;
636 static menuaction_s		s_keys_move_up_action;
637 static menuaction_s		s_keys_move_down_action;
638 static menuaction_s		s_keys_inventory_action;
639 static menuaction_s		s_keys_inv_use_action;
640 static menuaction_s		s_keys_inv_drop_action;
641 static menuaction_s		s_keys_inv_prev_action;
642 static menuaction_s		s_keys_inv_next_action;
643 
644 static menuaction_s		s_keys_help_computer_action;
645 
M_UnbindCommand(char * command)646 static void M_UnbindCommand (char *command)
647 {
648 	int		j;
649 	int		l;
650 	char	*b;
651 
652 	l = (int)strlen(command);
653 
654 	for (j=0 ; j<256 ; j++)
655 	{
656 		b = keybindings[j];
657 		if (!b)
658 			continue;
659 		if (!strncmp (b, command, l) )
660 			Key_SetBinding (j, "");
661 	}
662 }
663 
M_FindKeysForCommand(char * command,int * twokeys)664 static void M_FindKeysForCommand (char *command, int *twokeys)
665 {
666 	int		count;
667 	int		j;
668 	int		l;
669 	char	*b;
670 
671 	twokeys[0] = twokeys[1] = -1;
672 	l = (int)strlen(command);
673 	count = 0;
674 
675 	for (j=0 ; j<256 ; j++)
676 	{
677 		b = keybindings[j];
678 		if (!b)
679 			continue;
680 		if (!strncmp (b, command, l) )
681 		{
682 			twokeys[count] = j;
683 			count++;
684 			if (count == 2)
685 				break;
686 		}
687 	}
688 }
689 
KeyCursorDrawFunc(menuframework_s * menu)690 static void KeyCursorDrawFunc( menuframework_s *menu )
691 {
692 	if ( bind_grab )
693 		re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
694 	else
695 		re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
696 }
697 
DrawKeyBindingFunc(void * self)698 static void DrawKeyBindingFunc( void *self )
699 {
700 	int keys[2];
701 	menuaction_s *a = ( menuaction_s * ) self;
702 
703 	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
704 
705 	if (keys[0] == -1)
706 	{
707 		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
708 	}
709 	else
710 	{
711 		int x;
712 		const char *name;
713 
714 		name = Key_KeynumToString (keys[0]);
715 
716 		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
717 
718 		x = (int)strlen(name) * 8;
719 
720 		if (keys[1] != -1)
721 		{
722 			Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
723 			Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
724 		}
725 	}
726 }
727 
KeyBindingFunc(void * self)728 static void KeyBindingFunc( void *self )
729 {
730 	menuaction_s *a = ( menuaction_s * ) self;
731 	int keys[2];
732 
733 	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
734 
735 	if (keys[1] != -1)
736 		M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
737 
738 	bind_grab = true;
739 
740 	Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
741 }
742 
Keys_MenuInit(void)743 static void Keys_MenuInit( void )
744 {
745 	int y = 0;
746 	int i = 0;
747 
748 	s_keys_menu.x = (int)(viddef.width * 0.50f);
749 	s_keys_menu.nitems = 0;
750 	s_keys_menu.cursordraw = KeyCursorDrawFunc;
751 
752 	s_keys_attack_action.generic.type	= MTYPE_ACTION;
753 	s_keys_attack_action.generic.flags  = QMF_GRAYED;
754 	s_keys_attack_action.generic.x		= 0;
755 	s_keys_attack_action.generic.y		= y;
756 	s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
757 	s_keys_attack_action.generic.localdata[0] = i;
758 	s_keys_attack_action.generic.name	= bindnames[s_keys_attack_action.generic.localdata[0]][1];
759 
760 	s_keys_change_weapon_action.generic.type	= MTYPE_ACTION;
761 	s_keys_change_weapon_action.generic.flags  = QMF_GRAYED;
762 	s_keys_change_weapon_action.generic.x		= 0;
763 	s_keys_change_weapon_action.generic.y		= y += 9;
764 	s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
765 	s_keys_change_weapon_action.generic.localdata[0] = ++i;
766 	s_keys_change_weapon_action.generic.name	= bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
767 
768 	s_keys_walk_forward_action.generic.type	= MTYPE_ACTION;
769 	s_keys_walk_forward_action.generic.flags  = QMF_GRAYED;
770 	s_keys_walk_forward_action.generic.x		= 0;
771 	s_keys_walk_forward_action.generic.y		= y += 9;
772 	s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
773 	s_keys_walk_forward_action.generic.localdata[0] = ++i;
774 	s_keys_walk_forward_action.generic.name	= bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
775 
776 	s_keys_backpedal_action.generic.type	= MTYPE_ACTION;
777 	s_keys_backpedal_action.generic.flags  = QMF_GRAYED;
778 	s_keys_backpedal_action.generic.x		= 0;
779 	s_keys_backpedal_action.generic.y		= y += 9;
780 	s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
781 	s_keys_backpedal_action.generic.localdata[0] = ++i;
782 	s_keys_backpedal_action.generic.name	= bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
783 
784 	s_keys_turn_left_action.generic.type	= MTYPE_ACTION;
785 	s_keys_turn_left_action.generic.flags  = QMF_GRAYED;
786 	s_keys_turn_left_action.generic.x		= 0;
787 	s_keys_turn_left_action.generic.y		= y += 9;
788 	s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
789 	s_keys_turn_left_action.generic.localdata[0] = ++i;
790 	s_keys_turn_left_action.generic.name	= bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
791 
792 	s_keys_turn_right_action.generic.type	= MTYPE_ACTION;
793 	s_keys_turn_right_action.generic.flags  = QMF_GRAYED;
794 	s_keys_turn_right_action.generic.x		= 0;
795 	s_keys_turn_right_action.generic.y		= y += 9;
796 	s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
797 	s_keys_turn_right_action.generic.localdata[0] = ++i;
798 	s_keys_turn_right_action.generic.name	= bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
799 
800 	s_keys_run_action.generic.type	= MTYPE_ACTION;
801 	s_keys_run_action.generic.flags  = QMF_GRAYED;
802 	s_keys_run_action.generic.x		= 0;
803 	s_keys_run_action.generic.y		= y += 9;
804 	s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
805 	s_keys_run_action.generic.localdata[0] = ++i;
806 	s_keys_run_action.generic.name	= bindnames[s_keys_run_action.generic.localdata[0]][1];
807 
808 	s_keys_step_left_action.generic.type	= MTYPE_ACTION;
809 	s_keys_step_left_action.generic.flags  = QMF_GRAYED;
810 	s_keys_step_left_action.generic.x		= 0;
811 	s_keys_step_left_action.generic.y		= y += 9;
812 	s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
813 	s_keys_step_left_action.generic.localdata[0] = ++i;
814 	s_keys_step_left_action.generic.name	= bindnames[s_keys_step_left_action.generic.localdata[0]][1];
815 
816 	s_keys_step_right_action.generic.type	= MTYPE_ACTION;
817 	s_keys_step_right_action.generic.flags  = QMF_GRAYED;
818 	s_keys_step_right_action.generic.x		= 0;
819 	s_keys_step_right_action.generic.y		= y += 9;
820 	s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
821 	s_keys_step_right_action.generic.localdata[0] = ++i;
822 	s_keys_step_right_action.generic.name	= bindnames[s_keys_step_right_action.generic.localdata[0]][1];
823 
824 	s_keys_sidestep_action.generic.type	= MTYPE_ACTION;
825 	s_keys_sidestep_action.generic.flags  = QMF_GRAYED;
826 	s_keys_sidestep_action.generic.x		= 0;
827 	s_keys_sidestep_action.generic.y		= y += 9;
828 	s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
829 	s_keys_sidestep_action.generic.localdata[0] = ++i;
830 	s_keys_sidestep_action.generic.name	= bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
831 
832 	s_keys_look_up_action.generic.type	= MTYPE_ACTION;
833 	s_keys_look_up_action.generic.flags  = QMF_GRAYED;
834 	s_keys_look_up_action.generic.x		= 0;
835 	s_keys_look_up_action.generic.y		= y += 9;
836 	s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
837 	s_keys_look_up_action.generic.localdata[0] = ++i;
838 	s_keys_look_up_action.generic.name	= bindnames[s_keys_look_up_action.generic.localdata[0]][1];
839 
840 	s_keys_look_down_action.generic.type	= MTYPE_ACTION;
841 	s_keys_look_down_action.generic.flags  = QMF_GRAYED;
842 	s_keys_look_down_action.generic.x		= 0;
843 	s_keys_look_down_action.generic.y		= y += 9;
844 	s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
845 	s_keys_look_down_action.generic.localdata[0] = ++i;
846 	s_keys_look_down_action.generic.name	= bindnames[s_keys_look_down_action.generic.localdata[0]][1];
847 
848 	s_keys_center_view_action.generic.type	= MTYPE_ACTION;
849 	s_keys_center_view_action.generic.flags  = QMF_GRAYED;
850 	s_keys_center_view_action.generic.x		= 0;
851 	s_keys_center_view_action.generic.y		= y += 9;
852 	s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
853 	s_keys_center_view_action.generic.localdata[0] = ++i;
854 	s_keys_center_view_action.generic.name	= bindnames[s_keys_center_view_action.generic.localdata[0]][1];
855 
856 	s_keys_mouse_look_action.generic.type	= MTYPE_ACTION;
857 	s_keys_mouse_look_action.generic.flags  = QMF_GRAYED;
858 	s_keys_mouse_look_action.generic.x		= 0;
859 	s_keys_mouse_look_action.generic.y		= y += 9;
860 	s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
861 	s_keys_mouse_look_action.generic.localdata[0] = ++i;
862 	s_keys_mouse_look_action.generic.name	= bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
863 
864 	s_keys_keyboard_look_action.generic.type	= MTYPE_ACTION;
865 	s_keys_keyboard_look_action.generic.flags  = QMF_GRAYED;
866 	s_keys_keyboard_look_action.generic.x		= 0;
867 	s_keys_keyboard_look_action.generic.y		= y += 9;
868 	s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
869 	s_keys_keyboard_look_action.generic.localdata[0] = ++i;
870 	s_keys_keyboard_look_action.generic.name	= bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
871 
872 	s_keys_move_up_action.generic.type	= MTYPE_ACTION;
873 	s_keys_move_up_action.generic.flags  = QMF_GRAYED;
874 	s_keys_move_up_action.generic.x		= 0;
875 	s_keys_move_up_action.generic.y		= y += 9;
876 	s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
877 	s_keys_move_up_action.generic.localdata[0] = ++i;
878 	s_keys_move_up_action.generic.name	= bindnames[s_keys_move_up_action.generic.localdata[0]][1];
879 
880 	s_keys_move_down_action.generic.type	= MTYPE_ACTION;
881 	s_keys_move_down_action.generic.flags  = QMF_GRAYED;
882 	s_keys_move_down_action.generic.x		= 0;
883 	s_keys_move_down_action.generic.y		= y += 9;
884 	s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
885 	s_keys_move_down_action.generic.localdata[0] = ++i;
886 	s_keys_move_down_action.generic.name	= bindnames[s_keys_move_down_action.generic.localdata[0]][1];
887 
888 	s_keys_inventory_action.generic.type	= MTYPE_ACTION;
889 	s_keys_inventory_action.generic.flags  = QMF_GRAYED;
890 	s_keys_inventory_action.generic.x		= 0;
891 	s_keys_inventory_action.generic.y		= y += 9;
892 	s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
893 	s_keys_inventory_action.generic.localdata[0] = ++i;
894 	s_keys_inventory_action.generic.name	= bindnames[s_keys_inventory_action.generic.localdata[0]][1];
895 
896 	s_keys_inv_use_action.generic.type	= MTYPE_ACTION;
897 	s_keys_inv_use_action.generic.flags  = QMF_GRAYED;
898 	s_keys_inv_use_action.generic.x		= 0;
899 	s_keys_inv_use_action.generic.y		= y += 9;
900 	s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
901 	s_keys_inv_use_action.generic.localdata[0] = ++i;
902 	s_keys_inv_use_action.generic.name	= bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
903 
904 	s_keys_inv_drop_action.generic.type	= MTYPE_ACTION;
905 	s_keys_inv_drop_action.generic.flags  = QMF_GRAYED;
906 	s_keys_inv_drop_action.generic.x		= 0;
907 	s_keys_inv_drop_action.generic.y		= y += 9;
908 	s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
909 	s_keys_inv_drop_action.generic.localdata[0] = ++i;
910 	s_keys_inv_drop_action.generic.name	= bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
911 
912 	s_keys_inv_prev_action.generic.type	= MTYPE_ACTION;
913 	s_keys_inv_prev_action.generic.flags  = QMF_GRAYED;
914 	s_keys_inv_prev_action.generic.x		= 0;
915 	s_keys_inv_prev_action.generic.y		= y += 9;
916 	s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
917 	s_keys_inv_prev_action.generic.localdata[0] = ++i;
918 	s_keys_inv_prev_action.generic.name	= bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
919 
920 	s_keys_inv_next_action.generic.type	= MTYPE_ACTION;
921 	s_keys_inv_next_action.generic.flags  = QMF_GRAYED;
922 	s_keys_inv_next_action.generic.x		= 0;
923 	s_keys_inv_next_action.generic.y		= y += 9;
924 	s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
925 	s_keys_inv_next_action.generic.localdata[0] = ++i;
926 	s_keys_inv_next_action.generic.name	= bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
927 
928 	s_keys_help_computer_action.generic.type	= MTYPE_ACTION;
929 	s_keys_help_computer_action.generic.flags  = QMF_GRAYED;
930 	s_keys_help_computer_action.generic.x		= 0;
931 	s_keys_help_computer_action.generic.y		= y += 9;
932 	s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
933 	s_keys_help_computer_action.generic.localdata[0] = ++i;
934 	s_keys_help_computer_action.generic.name	= bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
935 
936 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
937 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
938 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
939 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
940 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
941 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
942 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
943 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
944 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
945 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
946 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
947 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
948 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
949 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
950 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
951 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
952 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
953 
954 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
955 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
956 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
957 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
958 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
959 
960 	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
961 
962 	Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
963 	Menu_Center( &s_keys_menu );
964 }
965 
Keys_MenuDraw(void)966 static void Keys_MenuDraw (void)
967 {
968 	Menu_AdjustCursor( &s_keys_menu, 1 );
969 	Menu_Draw( &s_keys_menu );
970 }
971 
Keys_MenuKey(int key)972 static const char *Keys_MenuKey( int key )
973 {
974 	menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
975 
976 	if ( bind_grab )
977 	{
978 		if ( key != K_ESCAPE && key != '`' )
979 		{
980 			char cmd[1024];
981 
982 			Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
983 			Cbuf_InsertText (cmd);
984 		}
985 
986 		Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
987 		bind_grab = false;
988 		return menu_out_sound;
989 	}
990 
991 	switch ( key )
992 	{
993 	case K_KP_ENTER:
994 	case K_ENTER:
995 		KeyBindingFunc( item );
996 		return menu_in_sound;
997 	case K_BACKSPACE:		// delete bindings
998 	case K_DEL:				// delete bindings
999 	case K_KP_DEL:
1000 		M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
1001 		return menu_out_sound;
1002 	default:
1003 		return Default_MenuKey( &s_keys_menu, key );
1004 	}
1005 }
1006 
M_Menu_Keys_f(void)1007 static void M_Menu_Keys_f (void)
1008 {
1009 	Keys_MenuInit();
1010 	M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
1011 }
1012 
1013 
1014 /*
1015 =======================================================================
1016 
1017 CONTROLS MENU
1018 
1019 =======================================================================
1020 */
1021 //static cvar_t *win_noalttab;
1022 #ifdef JOYSTICK
1023 extern cvar_t *in_joystick;
1024 #endif
1025 
1026 
1027 static menuframework_s	s_r1q2_options_menu;
1028 static menuseparator_s	s_r1q2_warning;
1029 static menuseparator_s	s_r1q2_warning2;
1030 
1031 #ifdef _WIN32
1032 static menulist_s		s_r1q2_dinput;
1033 static menulist_s		s_r1q2_winxp;
1034 #endif
1035 
1036 static menulist_s		s_r1q2_defer;
1037 static menulist_s		s_r1q2_async;
1038 static menulist_s		s_r1q2_autorecord;
1039 static menulist_s		s_r1q2_xaniarail;
1040 
1041 static menuframework_s	s_options_menu;
1042 static menuaction_s		s_options_r1q2_action;
1043 static menuaction_s		s_options_defaults_action;
1044 static menuaction_s		s_options_customize_options_action;
1045 static menufield_s		s_options_sensitivity_slider;
1046 static menulist_s		s_options_freelook_box;
1047 //static menulist_s		s_options_noalttab_box;
1048 static menulist_s		s_options_alwaysrun_box;
1049 static menulist_s		s_options_invertmouse_box;
1050 static menulist_s		s_options_lookspring_box;
1051 static menulist_s		s_options_lookstrafe_box;
1052 static menulist_s		s_options_crosshair_box;
1053 static menuslider_s		s_options_sfxvolume_slider;
1054 #ifdef JOYSTICK
1055 static menulist_s		s_options_joystick_box;
1056 #endif
1057 static menulist_s		s_options_cdvolume_box;
1058 static menulist_s		s_options_quality_list;
1059 static menulist_s		s_options_compatibility_list;
1060 static menulist_s		s_options_console_action;
1061 
CrosshairFunc(void * unused)1062 static void CrosshairFunc( void *unused )
1063 {
1064 	Cvar_SetValue( "crosshair", (float)s_options_crosshair_box.curvalue );
1065 }
1066 
1067 #ifdef JOYSTICK
JoystickFunc(void * unused)1068 static void JoystickFunc( void *unused )
1069 {
1070 	Cvar_SetValue( "in_joystick", (float)s_options_joystick_box.curvalue );
1071 }
1072 #endif
1073 
CustomizeControlsFunc(void * unused)1074 static void CustomizeControlsFunc( void *unused )
1075 {
1076 	M_Menu_Keys_f();
1077 }
1078 
1079 #ifdef _WIN32
DirectInputFunc(void * unused)1080 static void DirectInputFunc (void *unused)
1081 {
1082 	Cvar_SetValue ("m_directinput", (float)s_r1q2_dinput.curvalue);
1083 	IN_Restart_f();
1084 }
1085 
AccelFixFunc(void * unused)1086 static void AccelFixFunc (void *unused)
1087 {
1088 	Cvar_SetValue ("m_fixaccel", (float)s_r1q2_winxp.curvalue);
1089 	IN_Restart_f();
1090 }
1091 #endif
1092 
DeferFunc(void * unused)1093 static void DeferFunc (void *unused)
1094 {
1095 	Cvar_SetValue ("cl_defermodels", (float)s_r1q2_defer.curvalue);
1096 }
1097 
AsyncFunc(void * unused)1098 static void AsyncFunc (void *unused)
1099 {
1100 	Cvar_SetValue ("cl_async", (float)s_r1q2_async.curvalue);
1101 }
1102 
AutoFunc(void * unused)1103 static void AutoFunc (void *unused)
1104 {
1105 	Cvar_SetValue ("cl_autorecord", (float)s_r1q2_autorecord.curvalue);
1106 }
1107 
RailTrailFunc(void * unused)1108 static void RailTrailFunc (void *unused)
1109 {
1110 	Cvar_SetValue ("cl_railtrail", (float)s_r1q2_xaniarail.curvalue);
1111 }
1112 
1113 
R1Q2_MenuInit(void)1114 static void R1Q2_MenuInit (void)
1115 {
1116 	static const char *yesno_names[] =
1117 	{
1118 		"disabled",
1119 		"enabled",
1120 		0
1121 	};
1122 
1123 	static const char *xanianames[] =
1124 	{
1125 		"disabled",
1126 		"red",
1127 		"green",
1128 		"blue",
1129 		"yellow",
1130 		"orange",
1131 		0
1132 	};
1133 
1134 #ifdef _WIN32
1135 	static const char *dinputnames[] =
1136 	{
1137 		"disabled",
1138 		"buffered",
1139 		"immediate",
1140 		0
1141 	};
1142 #endif
1143 
1144 	/*
1145 	** configure controls menu and menu items
1146 	*/
1147 	s_r1q2_options_menu.x = viddef.width / 2;
1148 	s_r1q2_options_menu.y = viddef.height / 2 - 58;
1149 
1150 	s_r1q2_options_menu.nitems = 0;
1151 
1152 	s_r1q2_warning.generic.type = MTYPE_SEPARATOR;
1153 	s_r1q2_warning.generic.name = "WARNING: Settings here will not be saved. Any settings";
1154 	s_r1q2_warning.generic.x    = 160;
1155 	s_r1q2_warning.generic.y	 = 0;
1156 
1157 	s_r1q2_warning2.generic.type = MTYPE_SEPARATOR;
1158 	s_r1q2_warning2.generic.name = "that you wish to keep will need adding to a config.";
1159 	s_r1q2_warning2.generic.x    = 160;
1160 	s_r1q2_warning2.generic.y	 = 10;
1161 
1162 #ifdef _WIN32
1163 	s_r1q2_dinput.generic.type = MTYPE_SPINCONTROL;
1164 	s_r1q2_dinput.generic.x	= 0;
1165 	s_r1q2_dinput.generic.y	= 30;
1166 	s_r1q2_dinput.generic.name	= "directinput mouse";
1167 	s_r1q2_dinput.generic.callback = DirectInputFunc;
1168 	s_r1q2_dinput.itemnames = dinputnames;
1169 	s_r1q2_dinput.curvalue = (int)ClampCvar (0, 2, Cvar_VariableValue ("m_directinput"));
1170 
1171 	s_r1q2_winxp.generic.type = MTYPE_SPINCONTROL;
1172 	s_r1q2_winxp.generic.x	= 0;
1173 	s_r1q2_winxp.generic.y	= 40;
1174 	s_r1q2_winxp.generic.name	= "xp mouse acceleration fix";
1175 	s_r1q2_winxp.generic.callback = AccelFixFunc;
1176 	s_r1q2_winxp.itemnames = yesno_names;
1177 	s_r1q2_winxp.curvalue = (int)ClampCvar (0, 1, Cvar_VariableValue ("m_fixaccel"));
1178 #endif
1179 
1180 	s_r1q2_defer.generic.type = MTYPE_SPINCONTROL;
1181 	s_r1q2_defer.generic.x	= 0;
1182 	s_r1q2_defer.generic.y	= 60;
1183 	s_r1q2_defer.generic.name	= "defer model loading";
1184 	s_r1q2_defer.generic.callback = DeferFunc;
1185 	s_r1q2_defer.itemnames = yesno_names;
1186 	s_r1q2_defer.curvalue = (int)ClampCvar (0, 1, Cvar_VariableValue ("cl_defermodels"));
1187 
1188 	s_r1q2_async.generic.type = MTYPE_SPINCONTROL;
1189 	s_r1q2_async.generic.x	= 0;
1190 	s_r1q2_async.generic.y	= 70;
1191 	s_r1q2_async.generic.name	= "asynchronous net/fps";
1192 	s_r1q2_async.generic.callback = AsyncFunc;
1193 	s_r1q2_async.itemnames = yesno_names;
1194 	s_r1q2_async.curvalue = (int)ClampCvar (0, 1, Cvar_VariableValue ("cl_async"));
1195 
1196 	s_r1q2_autorecord.generic.type = MTYPE_SPINCONTROL;
1197 	s_r1q2_autorecord.generic.x	= 0;
1198 	s_r1q2_autorecord.generic.y	= 80;
1199 	s_r1q2_autorecord.generic.name	= "automatic demo record";
1200 	s_r1q2_autorecord.generic.callback = AutoFunc;
1201 	s_r1q2_autorecord.itemnames = yesno_names;
1202 	s_r1q2_autorecord.curvalue = (int)ClampCvar (0, 1, Cvar_VariableValue ("cl_autorecord"));
1203 
1204 	s_r1q2_xaniarail.generic.type = MTYPE_SPINCONTROL;
1205 	s_r1q2_xaniarail.generic.x	= 0;
1206 	s_r1q2_xaniarail.generic.y	= 90;
1207 	s_r1q2_xaniarail.generic.name	= "\"xania\" railgun trail";
1208 	s_r1q2_xaniarail.generic.callback = RailTrailFunc;
1209 	s_r1q2_xaniarail.itemnames = xanianames;
1210 	s_r1q2_xaniarail.curvalue = (int)ClampCvar (0, 5, Cvar_VariableValue ("cl_railtrail"));
1211 
1212 /*
1213 	s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
1214 	s_options_invertmouse_box.generic.x	= 0;
1215 	s_options_invertmouse_box.generic.y	= 70;
1216 	s_options_invertmouse_box.generic.name	= "invert mouse";
1217 	s_options_invertmouse_box.generic.callback = InvertMouseFunc;
1218 	s_options_invertmouse_box.itemnames = yesno_names;
1219 
1220 	s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
1221 	s_options_lookspring_box.generic.x	= 0;
1222 	s_options_lookspring_box.generic.y	= 80;
1223 	s_options_lookspring_box.generic.name	= "lookspring";
1224 	s_options_lookspring_box.generic.callback = LookspringFunc;
1225 	s_options_lookspring_box.itemnames = yesno_names;
1226 
1227 	s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
1228 	s_options_lookstrafe_box.generic.x	= 0;
1229 	s_options_lookstrafe_box.generic.y	= 90;
1230 	s_options_lookstrafe_box.generic.name	= "lookstrafe";
1231 	s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
1232 	s_options_lookstrafe_box.itemnames = yesno_names;
1233 
1234 	s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
1235 	s_options_freelook_box.generic.x	= 0;
1236 	s_options_freelook_box.generic.y	= 100;
1237 	s_options_freelook_box.generic.name	= "free look";
1238 	s_options_freelook_box.generic.callback = FreeLookFunc;
1239 	s_options_freelook_box.itemnames = yesno_names;
1240 
1241 	s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
1242 	s_options_crosshair_box.generic.x	= 0;
1243 	s_options_crosshair_box.generic.y	= 110;
1244 	s_options_crosshair_box.generic.name	= "crosshair";
1245 	s_options_crosshair_box.generic.callback = CrosshairFunc;
1246 	s_options_crosshair_box.itemnames = crosshair_names;
1247 */
1248 
1249 	Menu_AddItem (&s_r1q2_options_menu, (void *)&s_r1q2_warning);
1250 	Menu_AddItem (&s_r1q2_options_menu, (void *)&s_r1q2_warning2);
1251 
1252 #ifdef _WIN32
1253 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_dinput );
1254 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_winxp );
1255 #endif
1256 
1257 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_defer );
1258 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_async );
1259 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_autorecord );
1260 	Menu_AddItem( &s_r1q2_options_menu, ( void * ) &s_r1q2_xaniarail );
1261 }
1262 
R1Q2_MenuDraw(void)1263 static void R1Q2_MenuDraw (void)
1264 {
1265 	M_Banner ("m_banner_options");
1266 	Menu_AdjustCursor( &s_r1q2_options_menu, 2 );
1267 	Menu_Draw( &s_r1q2_options_menu );
1268 }
1269 
R1Q2_MenuKey(int key)1270 static const char *R1Q2_MenuKey( int key )
1271 {
1272 	return Default_MenuKey( &s_r1q2_options_menu, key );
1273 }
1274 
M_Menu_R1Q2_f(void)1275 static void M_Menu_R1Q2_f (void)
1276 {
1277 	R1Q2_MenuInit();
1278 	M_PushMenu ( R1Q2_MenuDraw, R1Q2_MenuKey);
1279 }
1280 
R1Q2OptionsMenu(void * unused)1281 static void R1Q2OptionsMenu ( void *unused )
1282 {
1283 	M_Menu_R1Q2_f();
1284 }
1285 
AlwaysRunFunc(void * unused)1286 static void AlwaysRunFunc( void *unused )
1287 {
1288 	Cvar_SetValue( "cl_run", (float)s_options_alwaysrun_box.curvalue );
1289 }
1290 
FreeLookFunc(void * unused)1291 static void FreeLookFunc( void *unused )
1292 {
1293 	Cvar_SetValue( "freelook", (float)s_options_freelook_box.curvalue );
1294 }
1295 
MouseSpeedFunc(void * unused)1296 static void MouseSpeedFunc( void *unused )
1297 {
1298 	float	value;
1299 
1300 	value = (float)atof(s_options_sensitivity_slider.buffer);
1301 
1302 	if (value < 2)
1303 		value = 2;
1304 
1305 	Cvar_SetValue( "sensitivity", value);
1306 }
1307 
1308 /*static void NoAltTabFunc( void *unused )
1309 {
1310 	Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
1311 }*/
1312 
1313 
ControlsSetMenuItemValues(void)1314 static void ControlsSetMenuItemValues( void )
1315 {
1316 	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
1317 	s_options_cdvolume_box.curvalue 		= !Cvar_IntValue("cd_nocd");
1318 	//s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
1319 	//strncpy (s_options_sensitivity_slider.buffer, sensitivity->string, sizeof(s_options_sensitivity_slider.buffer)-1);
1320 	snprintf (s_options_sensitivity_slider.buffer, sizeof(s_options_sensitivity_slider.buffer)-1, "%.3g", sensitivity->value);
1321 	//s_options_sensitivity_slider.curvalue	= ( sensitivity->value;
1322 
1323 	Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
1324 	s_options_alwaysrun_box.curvalue		= cl_run->intvalue;
1325 
1326 	s_options_invertmouse_box.curvalue		= m_pitch->value < 0;
1327 
1328 	Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
1329 	s_options_lookspring_box.curvalue		= lookspring->intvalue;
1330 
1331 	Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
1332 	s_options_lookstrafe_box.curvalue		= lookstrafe->intvalue;
1333 
1334 	Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
1335 	s_options_freelook_box.curvalue			= freelook->intvalue;
1336 
1337 	Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
1338 	s_options_crosshair_box.curvalue		= crosshair->intvalue;
1339 
1340 #ifdef JOYSTICK
1341 	Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
1342 	s_options_joystick_box.curvalue		= in_joystick->intvalue;
1343 #endif
1344 
1345 	//s_options_noalttab_box.curvalue			= win_noalttab->value;
1346 }
1347 
ControlsResetDefaultsFunc(void * unused)1348 static void ControlsResetDefaultsFunc( void *unused )
1349 {
1350 	Cbuf_AddText ("exec default.cfg\n");
1351 	Cbuf_Execute();
1352 
1353 	ControlsSetMenuItemValues();
1354 }
1355 
InvertMouseFunc(void * unused)1356 static void InvertMouseFunc( void *unused )
1357 {
1358 	Cvar_SetValue( "m_pitch", -m_pitch->value );
1359 }
1360 
LookspringFunc(void * unused)1361 static void LookspringFunc( void *unused )
1362 {
1363 	Cvar_SetValue( "lookspring", (float)!lookspring->value );
1364 }
1365 
LookstrafeFunc(void * unused)1366 static void LookstrafeFunc( void *unused )
1367 {
1368 	Cvar_SetValue( "lookstrafe", (float)!lookstrafe->value );
1369 }
1370 
UpdateVolumeFunc(void * unused)1371 static void UpdateVolumeFunc( void *unused )
1372 {
1373 	Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10.0f );
1374 }
1375 
UpdateCDVolumeFunc(void * unused)1376 static void UpdateCDVolumeFunc( void *unused )
1377 {
1378 	Cvar_SetValue( "cd_nocd", (float)!s_options_cdvolume_box.curvalue );
1379 }
1380 
1381 extern void Key_ClearTyping( void );
ConsoleFunc(void * unused)1382 static void ConsoleFunc( void *unused )
1383 {
1384 	/*
1385 	** the proper way to do this is probably to have ToggleConsole_f accept a parameter
1386 	*/
1387 
1388 	if ( cl.attractloop )
1389 	{
1390 		Cbuf_AddText ("killserver\n");
1391 		return;
1392 	}
1393 
1394 	Key_ClearTyping ();
1395 	Con_ClearNotify ();
1396 
1397 	M_ForceMenuOff ();
1398 	cls.key_dest = key_console;
1399 }
1400 
UpdateSoundQualityFunc(void * unused)1401 static void UpdateSoundQualityFunc( void *unused )
1402 {
1403 	if ( s_options_quality_list.curvalue == 2)
1404 	{
1405 		Cvar_Set ( "s_khz", "44" );
1406 		Cvar_Set ( "s_loadas8bit", "0" );
1407 	}
1408 	else if ( s_options_quality_list.curvalue == 1)
1409 	{
1410 		Cvar_Set ( "s_khz", "22" );
1411 		Cvar_Set ( "s_loadas8bit", "0" );
1412 	}
1413 	else
1414 	{
1415 		Cvar_Set ( "s_khz", "11" );
1416 		Cvar_Set ( "s_loadas8bit", "1" );
1417 	}
1418 
1419 	Cvar_SetValue( "s_primary", (float)s_options_compatibility_list.curvalue );
1420 
1421 	M_DrawTextBox( 8, 120 - 48, 36, 3 );
1422 	M_Print( 16 + 16, 120 - 48 + 8,  "Restarting the sound system. This" );
1423 	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
1424 	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
1425 
1426 	// the text box won't show up unless we do a buffer swap
1427 	re.EndFrame();
1428 
1429 	CL_Snd_Restart_f();
1430 }
1431 
Options_MenuInit(void)1432 static void Options_MenuInit( void )
1433 {
1434 	int squality;
1435 
1436 	static const char *cd_music_items[] =
1437 	{
1438 		"disabled",
1439 		"enabled",
1440 		0
1441 	};
1442 	static const char *quality_items[] =
1443 	{
1444 		"11 KHz", "22 KHz", "44 KHz", 0
1445 	};
1446 
1447 	static const char *compatibility_items[] =
1448 	{
1449 		"normal writing", "direct writing", 0
1450 	};
1451 
1452 	static const char *yesno_names[] =
1453 	{
1454 		"no",
1455 		"yes",
1456 		0
1457 	};
1458 
1459 	static const char *crosshair_names[] =
1460 	{
1461 		"none",
1462 		"cross",
1463 		"dot",
1464 		"angle",
1465 		0
1466 	};
1467 
1468 	//win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
1469 
1470 	squality = Cvar_IntValue ("s_khz");
1471 
1472 	switch (squality)	{
1473 		case 11:
1474 			squality = 0;
1475 			break;
1476 		case 22:
1477 			squality = 1;
1478 			break;
1479 		case 44:
1480 			squality = 2;
1481 			break;
1482 		default:
1483 			squality = 1;
1484 			break;
1485 	}
1486 
1487 	/*
1488 	** configure controls menu and menu items
1489 	*/
1490 	s_options_menu.x = viddef.width / 2;
1491 	s_options_menu.y = viddef.height / 2 - 58;
1492 	s_options_menu.nitems = 0;
1493 
1494 	s_options_sfxvolume_slider.generic.type	= MTYPE_SLIDER;
1495 	s_options_sfxvolume_slider.generic.x	= 0;
1496 	s_options_sfxvolume_slider.generic.y	= 0;
1497 	s_options_sfxvolume_slider.generic.name	= "effects volume";
1498 	s_options_sfxvolume_slider.generic.callback	= UpdateVolumeFunc;
1499 	s_options_sfxvolume_slider.minvalue		= 0;
1500 	s_options_sfxvolume_slider.maxvalue		= 10;
1501 	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
1502 
1503 	s_options_cdvolume_box.generic.type	= MTYPE_SPINCONTROL;
1504 	s_options_cdvolume_box.generic.x		= 0;
1505 	s_options_cdvolume_box.generic.y		= 10;
1506 	s_options_cdvolume_box.generic.name	= "CD music";
1507 	s_options_cdvolume_box.generic.callback	= UpdateCDVolumeFunc;
1508 	s_options_cdvolume_box.itemnames		= cd_music_items;
1509 	s_options_cdvolume_box.curvalue 		= !Cvar_IntValue("cd_nocd");
1510 
1511 	s_options_quality_list.generic.type	= MTYPE_SPINCONTROL;
1512 	s_options_quality_list.generic.x		= 0;
1513 	s_options_quality_list.generic.y		= 20;
1514 	s_options_quality_list.generic.name		= "sound quality";
1515 	s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
1516 	s_options_quality_list.itemnames		= quality_items;
1517 	s_options_quality_list.curvalue			= squality;
1518 
1519 	s_options_compatibility_list.generic.type	= MTYPE_SPINCONTROL;
1520 	s_options_compatibility_list.generic.x		= 0;
1521 	s_options_compatibility_list.generic.y		= 30;
1522 	s_options_compatibility_list.generic.name	= "sound compatibility";
1523 	s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
1524 	s_options_compatibility_list.itemnames		= compatibility_items;
1525 	s_options_compatibility_list.curvalue		= Cvar_IntValue( "s_primary" );
1526 
1527 	s_options_sensitivity_slider.generic.type	= MTYPE_FIELD;
1528 	s_options_sensitivity_slider.generic.flags = QMF_NUMBERSONLY;
1529 	s_options_sensitivity_slider.length = 3;
1530 	s_options_sensitivity_slider.visible_length = 3;
1531 	s_options_sensitivity_slider.generic.x		= 0;
1532 	s_options_sensitivity_slider.generic.y		= 50;
1533 	s_options_sensitivity_slider.generic.name	= "mouse speed";
1534 	//s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
1535 	//s_options_sensitivity_slider.minvalue		= 2;
1536 	//s_options_sensitivity_slider.maxvalue		= 22;
1537 
1538 	s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
1539 	s_options_alwaysrun_box.generic.x	= 0;
1540 	s_options_alwaysrun_box.generic.y	= 60;
1541 	s_options_alwaysrun_box.generic.name	= "always run";
1542 	s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
1543 	s_options_alwaysrun_box.itemnames = yesno_names;
1544 
1545 	s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
1546 	s_options_invertmouse_box.generic.x	= 0;
1547 	s_options_invertmouse_box.generic.y	= 70;
1548 	s_options_invertmouse_box.generic.name	= "invert mouse";
1549 	s_options_invertmouse_box.generic.callback = InvertMouseFunc;
1550 	s_options_invertmouse_box.itemnames = yesno_names;
1551 
1552 	s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
1553 	s_options_lookspring_box.generic.x	= 0;
1554 	s_options_lookspring_box.generic.y	= 80;
1555 	s_options_lookspring_box.generic.name	= "lookspring";
1556 	s_options_lookspring_box.generic.callback = LookspringFunc;
1557 	s_options_lookspring_box.itemnames = yesno_names;
1558 
1559 	s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
1560 	s_options_lookstrafe_box.generic.x	= 0;
1561 	s_options_lookstrafe_box.generic.y	= 90;
1562 	s_options_lookstrafe_box.generic.name	= "lookstrafe";
1563 	s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
1564 	s_options_lookstrafe_box.itemnames = yesno_names;
1565 
1566 	s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
1567 	s_options_freelook_box.generic.x	= 0;
1568 	s_options_freelook_box.generic.y	= 100;
1569 	s_options_freelook_box.generic.name	= "free look";
1570 	s_options_freelook_box.generic.callback = FreeLookFunc;
1571 	s_options_freelook_box.itemnames = yesno_names;
1572 
1573 	s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
1574 	s_options_crosshair_box.generic.x	= 0;
1575 	s_options_crosshair_box.generic.y	= 110;
1576 	s_options_crosshair_box.generic.name	= "crosshair";
1577 	s_options_crosshair_box.generic.callback = CrosshairFunc;
1578 	s_options_crosshair_box.itemnames = crosshair_names;
1579 /*
1580 	s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
1581 	s_options_noalttab_box.generic.x	= 0;
1582 	s_options_noalttab_box.generic.y	= 110;
1583 	s_options_noalttab_box.generic.name	= "disable alt-tab";
1584 	s_options_noalttab_box.generic.callback = NoAltTabFunc;
1585 	s_options_noalttab_box.itemnames = yesno_names;
1586 */
1587 #ifdef JOYSTICK
1588 	s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
1589 	s_options_joystick_box.generic.x	= 0;
1590 	s_options_joystick_box.generic.y	= 120;
1591 	s_options_joystick_box.generic.name	= "use joystick";
1592 	s_options_joystick_box.generic.callback = JoystickFunc;
1593 	s_options_joystick_box.itemnames = yesno_names;
1594 #endif
1595 
1596 	s_options_r1q2_action.generic.type = MTYPE_ACTION;
1597 	s_options_r1q2_action.generic.x		= 0;
1598 	s_options_r1q2_action.generic.y		= 140;
1599 	s_options_r1q2_action.generic.name	= PRODUCTNAMELOWER " options";
1600 	s_options_r1q2_action.generic.callback = R1Q2OptionsMenu;
1601 
1602 	s_options_customize_options_action.generic.type	= MTYPE_ACTION;
1603 	s_options_customize_options_action.generic.x		= 0;
1604 	s_options_customize_options_action.generic.y		= 160;
1605 	s_options_customize_options_action.generic.name	= "customize controls";
1606 	s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
1607 
1608 	s_options_defaults_action.generic.type	= MTYPE_ACTION;
1609 	s_options_defaults_action.generic.x		= 0;
1610 	s_options_defaults_action.generic.y		= 170;
1611 	s_options_defaults_action.generic.name	= "reset defaults";
1612 	s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
1613 
1614 	s_options_console_action.generic.type	= MTYPE_ACTION;
1615 	s_options_console_action.generic.x		= 0;
1616 	s_options_console_action.generic.y		= 180;
1617 	s_options_console_action.generic.name	= "go to console";
1618 	s_options_console_action.generic.callback = ConsoleFunc;
1619 
1620 	ControlsSetMenuItemValues();
1621 
1622 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
1623 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
1624 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
1625 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
1626 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
1627 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
1628 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
1629 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
1630 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
1631 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
1632 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
1633 #ifdef JOYSTICK
1634 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
1635 #endif
1636 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_r1q2_action );
1637 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
1638 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
1639 	Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
1640 }
1641 
Options_MenuDraw(void)1642 static void Options_MenuDraw (void)
1643 {
1644 	M_Banner( "m_banner_options" );
1645 	Menu_AdjustCursor( &s_options_menu, 1 );
1646 	Menu_Draw( &s_options_menu );
1647 }
1648 
Options_MenuKey(int key)1649 static const char *Options_MenuKey( int key )
1650 {
1651 	if (key == K_ESCAPE)
1652 		MouseSpeedFunc (NULL);
1653 
1654 	return Default_MenuKey( &s_options_menu, key );
1655 }
1656 
M_Menu_Options_f(void)1657 static void M_Menu_Options_f (void)
1658 {
1659 	Options_MenuInit();
1660 	M_PushMenu ( Options_MenuDraw, Options_MenuKey );
1661 }
1662 
1663 /*
1664 =======================================================================
1665 
1666 VIDEO MENU
1667 
1668 =======================================================================
1669 */
1670 
M_Menu_Video_f(void)1671 static void M_Menu_Video_f (void)
1672 {
1673 	VID_MenuInit();
1674 	M_PushMenu( VID_MenuDraw, VID_MenuKey );
1675 }
1676 
1677 /*
1678 =============================================================================
1679 
1680 END GAME MENU
1681 
1682 =============================================================================
1683 */
1684 static int credits_start_time;
1685 static const char **credits;
1686 static char *creditsIndex[256];
1687 static char *creditsBuffer;
1688 static const char *idcredits[] =
1689 {
1690 	"+QUAKE II BY ID SOFTWARE",
1691 	"",
1692 	"+PROGRAMMING",
1693 	"John Carmack",
1694 	"John Cash",
1695 	"Brian Hook",
1696 	"",
1697 	"+ART",
1698 	"Adrian Carmack",
1699 	"Kevin Cloud",
1700 	"Paul Steed",
1701 	"",
1702 	"+LEVEL DESIGN",
1703 	"Tim Willits",
1704 	"American McGee",
1705 	"Christian Antkow",
1706 	"Paul Jaquays",
1707 	"Brandon James",
1708 	"",
1709 	"+BIZ",
1710 	"Todd Hollenshead",
1711 	"Barrett (Bear) Alexander",
1712 	"Donna Jackson",
1713 	"",
1714 	"",
1715 	"+SPECIAL THANKS",
1716 	"Ben Donges for beta testing",
1717 	"",
1718 	"",
1719 	"",
1720 	"",
1721 	"",
1722 	"",
1723 	"+ADDITIONAL SUPPORT",
1724 	"",
1725 	"+LINUX PORT AND CTF",
1726 	"Dave \"Zoid\" Kirsch",
1727 	"",
1728 	"+CINEMATIC SEQUENCES",
1729 	"Ending Cinematic by Blur Studio - ",
1730 	"Venice, CA",
1731 	"",
1732 	"Environment models for Introduction",
1733 	"Cinematic by Karl Dolgener",
1734 	"",
1735 	"Assistance with environment design",
1736 	"by Cliff Iwai",
1737 	"",
1738 	"+SOUND EFFECTS AND MUSIC",
1739 	"Sound Design by Soundelux Media Labs.",
1740 	"Music Composed and Produced by",
1741 	"Soundelux Media Labs.  Special thanks",
1742 	"to Bill Brown, Tom Ozanich, Brian",
1743 	"Celano, Jeff Eisner, and The Soundelux",
1744 	"Players.",
1745 	"",
1746 	"\"Level Music\" by Sonic Mayhem",
1747 	"www.sonicmayhem.com",
1748 	"",
1749 	"\"Quake II Theme Song\"",
1750 	"(C) 1997 Rob Zombie. All Rights",
1751 	"Reserved.",
1752 	"",
1753 	"Track 10 (\"Climb\") by Jer Sypult",
1754 	"",
1755 	"Voice of computers by",
1756 	"Carly Staehlin-Taylor",
1757 	"",
1758 	"+THANKS TO ACTIVISION",
1759 	"+IN PARTICULAR:",
1760 	"",
1761 	"John Tam",
1762 	"Steve Rosenthal",
1763 	"Marty Stratton",
1764 	"Henk Hartong",
1765 	"",
1766 	"Quake II(tm) (C)1997 Id Software, Inc.",
1767 	"All Rights Reserved.  Distributed by",
1768 	"Activision, Inc. under license.",
1769 	"Quake II(tm), the Id Software name,",
1770 	"the \"Q II\"(tm) logo and id(tm)",
1771 	"logo are trademarks of Id Software,",
1772 	"Inc. Activision(R) is a registered",
1773 	"trademark of Activision, Inc. All",
1774 	"other trademarks and trade names are",
1775 	"properties of their respective owners.",
1776 	0
1777 };
1778 
1779 static const char *xatcredits[] =
1780 {
1781 	"+QUAKE II MISSION PACK: THE RECKONING",
1782 	"+BY",
1783 	"+XATRIX ENTERTAINMENT, INC.",
1784 	"",
1785 	"+DESIGN AND DIRECTION",
1786 	"Drew Markham",
1787 	"",
1788 	"+PRODUCED BY",
1789 	"Greg Goodrich",
1790 	"",
1791 	"+PROGRAMMING",
1792 	"Rafael Paiz",
1793 	"",
1794 	"+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
1795 	"Alex Mayberry",
1796 	"",
1797 	"+LEVEL DESIGN",
1798 	"Mal Blackwell",
1799 	"Dan Koppel",
1800 	"",
1801 	"+ART DIRECTION",
1802 	"Michael \"Maxx\" Kaufman",
1803 	"",
1804 	"+COMPUTER GRAPHICS SUPERVISOR AND",
1805 	"+CHARACTER ANIMATION DIRECTION",
1806 	"Barry Dempsey",
1807 	"",
1808 	"+SENIOR ANIMATOR AND MODELER",
1809 	"Jason Hoover",
1810 	"",
1811 	"+CHARACTER ANIMATION AND",
1812 	"+MOTION CAPTURE SPECIALIST",
1813 	"Amit Doron",
1814 	"",
1815 	"+ART",
1816 	"Claire Praderie-Markham",
1817 	"Viktor Antonov",
1818 	"Corky Lehmkuhl",
1819 	"",
1820 	"+INTRODUCTION ANIMATION",
1821 	"Dominique Drozdz",
1822 	"",
1823 	"+ADDITIONAL LEVEL DESIGN",
1824 	"Aaron Barber",
1825 	"Rhett Baldwin",
1826 	"",
1827 	"+3D CHARACTER ANIMATION TOOLS",
1828 	"Gerry Tyra, SA Technology",
1829 	"",
1830 	"+ADDITIONAL EDITOR TOOL PROGRAMMING",
1831 	"Robert Duffy",
1832 	"",
1833 	"+ADDITIONAL PROGRAMMING",
1834 	"Ryan Feltrin",
1835 	"",
1836 	"+PRODUCTION COORDINATOR",
1837 	"Victoria Sylvester",
1838 	"",
1839 	"+SOUND DESIGN",
1840 	"Gary Bradfield",
1841 	"",
1842 	"+MUSIC BY",
1843 	"Sonic Mayhem",
1844 	"",
1845 	"",
1846 	"",
1847 	"+SPECIAL THANKS",
1848 	"+TO",
1849 	"+OUR FRIENDS AT ID SOFTWARE",
1850 	"",
1851 	"John Carmack",
1852 	"John Cash",
1853 	"Brian Hook",
1854 	"Adrian Carmack",
1855 	"Kevin Cloud",
1856 	"Paul Steed",
1857 	"Tim Willits",
1858 	"Christian Antkow",
1859 	"Paul Jaquays",
1860 	"Brandon James",
1861 	"Todd Hollenshead",
1862 	"Barrett (Bear) Alexander",
1863 	"Dave \"Zoid\" Kirsch",
1864 	"Donna Jackson",
1865 	"",
1866 	"",
1867 	"",
1868 	"+THANKS TO ACTIVISION",
1869 	"+IN PARTICULAR:",
1870 	"",
1871 	"Marty Stratton",
1872 	"Henk \"The Original Ripper\" Hartong",
1873 	"Kevin Kraff",
1874 	"Jamey Gottlieb",
1875 	"Chris Hepburn",
1876 	"",
1877 	"+AND THE GAME TESTERS",
1878 	"",
1879 	"Tim Vanlaw",
1880 	"Doug Jacobs",
1881 	"Steven Rosenthal",
1882 	"David Baker",
1883 	"Chris Campbell",
1884 	"Aaron Casillas",
1885 	"Steve Elwell",
1886 	"Derek Johnstone",
1887 	"Igor Krinitskiy",
1888 	"Samantha Lee",
1889 	"Michael Spann",
1890 	"Chris Toft",
1891 	"Juan Valdes",
1892 	"",
1893 	"+THANKS TO INTERGRAPH COMPUTER SYTEMS",
1894 	"+IN PARTICULAR:",
1895 	"",
1896 	"Michael T. Nicolaou",
1897 	"",
1898 	"",
1899 	"Quake II Mission Pack: The Reckoning",
1900 	"(tm) (C)1998 Id Software, Inc. All",
1901 	"Rights Reserved. Developed by Xatrix",
1902 	"Entertainment, Inc. for Id Software,",
1903 	"Inc. Distributed by Activision Inc.",
1904 	"under license. Quake(R) is a",
1905 	"registered trademark of Id Software,",
1906 	"Inc. Quake II Mission Pack: The",
1907 	"Reckoning(tm), Quake II(tm), the Id",
1908 	"Software name, the \"Q II\"(tm) logo",
1909 	"and id(tm) logo are trademarks of Id",
1910 	"Software, Inc. Activision(R) is a",
1911 	"registered trademark of Activision,",
1912 	"Inc. Xatrix(R) is a registered",
1913 	"trademark of Xatrix Entertainment,",
1914 	"Inc. All other trademarks and trade",
1915 	"names are properties of their",
1916 	"respective owners.",
1917 	0
1918 };
1919 
1920 static const char *roguecredits[] =
1921 {
1922 	"+QUAKE II MISSION PACK 2: GROUND ZERO",
1923 	"+BY",
1924 	"+ROGUE ENTERTAINMENT, INC.",
1925 	"",
1926 	"+PRODUCED BY",
1927 	"Jim Molinets",
1928 	"",
1929 	"+PROGRAMMING",
1930 	"Peter Mack",
1931 	"Patrick Magruder",
1932 	"",
1933 	"+LEVEL DESIGN",
1934 	"Jim Molinets",
1935 	"Cameron Lamprecht",
1936 	"Berenger Fish",
1937 	"Robert Selitto",
1938 	"Steve Tietze",
1939 	"Steve Thoms",
1940 	"",
1941 	"+ART DIRECTION",
1942 	"Rich Fleider",
1943 	"",
1944 	"+ART",
1945 	"Rich Fleider",
1946 	"Steve Maines",
1947 	"Won Choi",
1948 	"",
1949 	"+ANIMATION SEQUENCES",
1950 	"Creat Studios",
1951 	"Steve Maines",
1952 	"",
1953 	"+ADDITIONAL LEVEL DESIGN",
1954 	"Rich Fleider",
1955 	"Steve Maines",
1956 	"Peter Mack",
1957 	"",
1958 	"+SOUND",
1959 	"James Grunke",
1960 	"",
1961 	"+GROUND ZERO THEME",
1962 	"+AND",
1963 	"+MUSIC BY",
1964 	"Sonic Mayhem",
1965 	"",
1966 	"+VWEP MODELS",
1967 	"Brent \"Hentai\" Dill",
1968 	"",
1969 	"",
1970 	"",
1971 	"+SPECIAL THANKS",
1972 	"+TO",
1973 	"+OUR FRIENDS AT ID SOFTWARE",
1974 	"",
1975 	"John Carmack",
1976 	"John Cash",
1977 	"Brian Hook",
1978 	"Adrian Carmack",
1979 	"Kevin Cloud",
1980 	"Paul Steed",
1981 	"Tim Willits",
1982 	"Christian Antkow",
1983 	"Paul Jaquays",
1984 	"Brandon James",
1985 	"Todd Hollenshead",
1986 	"Barrett (Bear) Alexander",
1987 	"Katherine Anna Kang",
1988 	"Donna Jackson",
1989 	"Dave \"Zoid\" Kirsch",
1990 	"",
1991 	"",
1992 	"",
1993 	"+THANKS TO ACTIVISION",
1994 	"+IN PARTICULAR:",
1995 	"",
1996 	"Marty Stratton",
1997 	"Henk Hartong",
1998 	"Mitch Lasky",
1999 	"Steve Rosenthal",
2000 	"Steve Elwell",
2001 	"",
2002 	"+AND THE GAME TESTERS",
2003 	"",
2004 	"The Ranger Clan",
2005 	"Dave \"Zoid\" Kirsch",
2006 	"Nihilistic Software",
2007 	"Robert Duffy",
2008 	"",
2009 	"And Countless Others",
2010 	"",
2011 	"",
2012 	"",
2013 	"Quake II Mission Pack 2: Ground Zero",
2014 	"(tm) (C)1998 Id Software, Inc. All",
2015 	"Rights Reserved. Developed by Rogue",
2016 	"Entertainment, Inc. for Id Software,",
2017 	"Inc. Distributed by Activision Inc.",
2018 	"under license. Quake(R) is a",
2019 	"registered trademark of Id Software,",
2020 	"Inc. Quake II Mission Pack 2: Ground",
2021 	"Zero(tm), Quake II(tm), the Id",
2022 	"Software name, the \"Q II\"(tm) logo",
2023 	"and id(tm) logo are trademarks of Id",
2024 	"Software, Inc. Activision(R) is a",
2025 	"registered trademark of Activision,",
2026 	"Inc. Rogue(R) is a registered",
2027 	"trademark of Rogue Entertainment,",
2028 	"Inc. All other trademarks and trade",
2029 	"names are properties of their",
2030 	"respective owners.",
2031 	0
2032 };
2033 
2034 
M_Credits_MenuDraw(void)2035 static void M_Credits_MenuDraw( void )
2036 {
2037 	int i, y;
2038 
2039 	/*
2040 	** draw the credits
2041 	*/
2042 	for ( i = 0, y = (int)(viddef.height - ( ( cls.realtime - credits_start_time ) / 40.0F )); credits[i] && y < viddef.height; y += 10, i++ )
2043 	{
2044 		int j, stringoffset = 0;
2045 		int bold = false;
2046 
2047 		if ( y <= -8 )
2048 			continue;
2049 
2050 		if ( credits[i][0] == '+' )
2051 		{
2052 			bold = true;
2053 			stringoffset = 1;
2054 		}
2055 		else
2056 		{
2057 			bold = false;
2058 			stringoffset = 0;
2059 		}
2060 
2061 		for ( j = 0; credits[i][j+stringoffset]; j++ )
2062 		{
2063 			int x;
2064 
2065 			x = ( viddef.width - (int)strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
2066 
2067 			if ( bold )
2068 				re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
2069 			else
2070 				re.DrawChar( x, y, credits[i][j+stringoffset] );
2071 		}
2072 	}
2073 
2074 	if ( y < 0 )
2075 		credits_start_time = cls.realtime;
2076 }
2077 
M_Credits_Key(int key)2078 static const char *M_Credits_Key( int key )
2079 {
2080 	switch (key)
2081 	{
2082 	case K_ESCAPE:
2083 		if (creditsBuffer)
2084 			FS_FreeFile (creditsBuffer);
2085 		M_PopMenu ();
2086 		break;
2087 	}
2088 
2089 	return menu_out_sound;
2090 
2091 }
2092 
2093 extern int Developer_searchpath (void);
2094 
M_Menu_Credits_f(void)2095 static void M_Menu_Credits_f( void )
2096 {
2097 	int		n;
2098 	int		count;
2099 	char	*p;
2100 	int		isdeveloper = 0;
2101 
2102 	creditsBuffer = NULL;
2103 	count = FS_LoadFile ("credits", (void **)&creditsBuffer);
2104 	if (count != -1)
2105 	{
2106 		p = creditsBuffer;
2107 		for (n = 0; n < 255; n++)
2108 		{
2109 			creditsIndex[n] = p;
2110 			while (*p != '\r' && *p != '\n')
2111 			{
2112 				p++;
2113 				if (--count == 0)
2114 					break;
2115 			}
2116 			if (*p == '\r')
2117 			{
2118 				*p++ = 0;
2119 				if (--count == 0)
2120 					break;
2121 			}
2122 			*p++ = 0;
2123 			if (--count == 0)
2124 				break;
2125 		}
2126 		creditsIndex[++n] = 0;
2127 		credits = (const char **)creditsIndex;
2128 	}
2129 	else
2130 	{
2131 		isdeveloper = Developer_searchpath ();
2132 
2133 		if (isdeveloper == 1)			// xatrix
2134 			credits = xatcredits;
2135 		else if (isdeveloper == 2)		// ROGUE
2136 			credits = roguecredits;
2137 		else
2138 		{
2139 			credits = idcredits;
2140 		}
2141 
2142 	}
2143 
2144 	credits_start_time = cls.realtime;
2145 	M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
2146 }
2147 
2148 /*
2149 =============================================================================
2150 
2151 GAME MENU
2152 
2153 =============================================================================
2154 */
2155 
2156 //static int		m_game_cursor;
2157 
2158 static menuframework_s	s_game_menu;
2159 static menuaction_s		s_easy_game_action;
2160 static menuaction_s		s_medium_game_action;
2161 static menuaction_s		s_hard_game_action;
2162 static menuaction_s		s_load_game_action;
2163 static menuaction_s		s_save_game_action;
2164 static menuaction_s		s_credits_action;
2165 static menuseparator_s	s_blankline;
2166 
StartGame(void)2167 static void StartGame( void )
2168 {
2169 	if (!CM_MapWillLoad ("base1"))
2170 	{
2171 		Com_Printf ("ERROR: Your Quake II installation is missing the single player data, you cannot start a single player game.\n", LOG_GENERAL);
2172 		M_PopMenu ();
2173 		return;
2174 	}
2175 
2176 	// disable updates and start the cinematic going
2177 	cl.servercount = -1;
2178 	M_ForceMenuOff ();
2179 	Cvar_SetValue( "deathmatch", 0 );
2180 	Cvar_SetValue( "coop", 0 );
2181 
2182 	//Cvar_SetValue( "gamerules", 0 );		//PGM
2183 
2184 	Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
2185 	cls.key_dest = key_game;
2186 }
2187 
EasyGameFunc(void * data)2188 static void EasyGameFunc( void *data )
2189 {
2190 	Cvar_ForceSet( "skill", "0" );
2191 	StartGame();
2192 }
2193 
MediumGameFunc(void * data)2194 static void MediumGameFunc( void *data )
2195 {
2196 	Cvar_ForceSet( "skill", "1" );
2197 	StartGame();
2198 }
2199 
HardGameFunc(void * data)2200 static void HardGameFunc( void *data )
2201 {
2202 	Cvar_ForceSet( "skill", "2" );
2203 	StartGame();
2204 }
2205 
LoadGameFunc(void * unused)2206 static void LoadGameFunc( void *unused )
2207 {
2208 	M_Menu_LoadGame_f ();
2209 }
2210 
SaveGameFunc(void * unused)2211 static void SaveGameFunc( void *unused )
2212 {
2213 	M_Menu_SaveGame_f();
2214 }
2215 
CreditsFunc(void * unused)2216 static void CreditsFunc( void *unused )
2217 {
2218 	M_Menu_Credits_f();
2219 }
2220 
Game_MenuInit(void)2221 static void Game_MenuInit( void )
2222 {
2223 	/*static const char *difficulty_names[] =
2224 	{
2225 		"easy",
2226 		"medium",
2227 		"hard",
2228 		0
2229 	};*/
2230 
2231 	s_game_menu.x = (int)(viddef.width * 0.50f);
2232 	s_game_menu.nitems = 0;
2233 
2234 	s_easy_game_action.generic.type	= MTYPE_ACTION;
2235 	s_easy_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
2236 	s_easy_game_action.generic.x		= 0;
2237 	s_easy_game_action.generic.y		= 0;
2238 	s_easy_game_action.generic.name	= "easy";
2239 	s_easy_game_action.generic.callback = EasyGameFunc;
2240 
2241 	s_medium_game_action.generic.type	= MTYPE_ACTION;
2242 	s_medium_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
2243 	s_medium_game_action.generic.x		= 0;
2244 	s_medium_game_action.generic.y		= 10;
2245 	s_medium_game_action.generic.name	= "medium";
2246 	s_medium_game_action.generic.callback = MediumGameFunc;
2247 
2248 	s_hard_game_action.generic.type	= MTYPE_ACTION;
2249 	s_hard_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
2250 	s_hard_game_action.generic.x		= 0;
2251 	s_hard_game_action.generic.y		= 20;
2252 	s_hard_game_action.generic.name	= "hard";
2253 	s_hard_game_action.generic.callback = HardGameFunc;
2254 
2255 	s_blankline.generic.type = MTYPE_SEPARATOR;
2256 
2257 	s_load_game_action.generic.type	= MTYPE_ACTION;
2258 	s_load_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
2259 	s_load_game_action.generic.x		= 0;
2260 	s_load_game_action.generic.y		= 40;
2261 	s_load_game_action.generic.name	= "load game";
2262 	s_load_game_action.generic.callback = LoadGameFunc;
2263 
2264 	s_save_game_action.generic.type	= MTYPE_ACTION;
2265 	s_save_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
2266 	s_save_game_action.generic.x		= 0;
2267 	s_save_game_action.generic.y		= 50;
2268 	s_save_game_action.generic.name	= "save game";
2269 	s_save_game_action.generic.callback = SaveGameFunc;
2270 
2271 	s_credits_action.generic.type	= MTYPE_ACTION;
2272 	s_credits_action.generic.flags  = QMF_LEFT_JUSTIFY;
2273 	s_credits_action.generic.x		= 0;
2274 	s_credits_action.generic.y		= 60;
2275 	s_credits_action.generic.name	= "credits";
2276 	s_credits_action.generic.callback = CreditsFunc;
2277 
2278 	Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
2279 	Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
2280 	Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
2281 	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
2282 	Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
2283 	Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
2284 	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
2285 	Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
2286 
2287 	Menu_Center( &s_game_menu );
2288 }
2289 
Game_MenuDraw(void)2290 static void Game_MenuDraw( void )
2291 {
2292 	M_Banner( "m_banner_game" );
2293 	Menu_AdjustCursor( &s_game_menu, 1 );
2294 	Menu_Draw( &s_game_menu );
2295 }
2296 
Game_MenuKey(int key)2297 static const char *Game_MenuKey( int key )
2298 {
2299 	return Default_MenuKey( &s_game_menu, key );
2300 }
2301 
M_Menu_Game_f(void)2302 static void M_Menu_Game_f (void)
2303 {
2304 	Game_MenuInit();
2305 	M_PushMenu( Game_MenuDraw, Game_MenuKey );
2306 	//m_game_cursor = 1;
2307 }
2308 
2309 /*
2310 =============================================================================
2311 
2312 LOADGAME MENU
2313 
2314 =============================================================================
2315 */
2316 
2317 #define	MAX_SAVEGAMES	15
2318 
2319 static menuframework_s	s_savegame_menu;
2320 
2321 static menuframework_s	s_loadgame_menu;
2322 static menuaction_s		s_loadgame_actions[MAX_SAVEGAMES];
2323 
2324 char		m_savestrings[MAX_SAVEGAMES][32];
2325 qboolean	m_savevalid[MAX_SAVEGAMES];
2326 
Create_Savestrings(void)2327 static void Create_Savestrings (void)
2328 {
2329 	int		i;
2330 	FILE	*f;
2331 	char	name[MAX_OSPATH];
2332 
2333 	for (i=0 ; i<MAX_SAVEGAMES ; i++)
2334 	{
2335 		Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
2336 		f = fopen (name, "rb");
2337 		if (!f)
2338 		{
2339 			strcpy (m_savestrings[i], "<EMPTY>");
2340 			m_savevalid[i] = false;
2341 		}
2342 		else
2343 		{
2344 			FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
2345 			fclose (f);
2346 			m_savevalid[i] = true;
2347 		}
2348 	}
2349 }
2350 
LoadGameCallback(void * self)2351 static void LoadGameCallback( void *self )
2352 {
2353 	menuaction_s *a = ( menuaction_s * ) self;
2354 
2355 	if ( m_savevalid[ a->generic.localdata[0] ] )
2356 		Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
2357 	M_ForceMenuOff ();
2358 }
2359 
LoadGame_MenuInit(void)2360 static void LoadGame_MenuInit( void )
2361 {
2362 	int i;
2363 
2364 	s_loadgame_menu.x = viddef.width / 2 - 120;
2365 	s_loadgame_menu.y = viddef.height / 2 - 58;
2366 	s_loadgame_menu.nitems = 0;
2367 
2368 	Create_Savestrings();
2369 
2370 	for ( i = 0; i < MAX_SAVEGAMES; i++ )
2371 	{
2372 		s_loadgame_actions[i].generic.name			= m_savestrings[i];
2373 		s_loadgame_actions[i].generic.flags			= QMF_LEFT_JUSTIFY;
2374 		s_loadgame_actions[i].generic.localdata[0]	= i;
2375 		s_loadgame_actions[i].generic.callback		= LoadGameCallback;
2376 
2377 		s_loadgame_actions[i].generic.x = 0;
2378 		s_loadgame_actions[i].generic.y = ( i ) * 10;
2379 		if (i>0)	// separate from autosave
2380 			s_loadgame_actions[i].generic.y += 10;
2381 
2382 		s_loadgame_actions[i].generic.type = MTYPE_ACTION;
2383 
2384 		Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
2385 	}
2386 }
2387 
LoadGame_MenuDraw(void)2388 static void LoadGame_MenuDraw( void )
2389 {
2390 	M_Banner( "m_banner_load_game" );
2391 //	Menu_AdjustCursor( &s_loadgame_menu, 1 );
2392 	Menu_Draw( &s_loadgame_menu );
2393 }
2394 
LoadGame_MenuKey(int key)2395 static const char *LoadGame_MenuKey( int key )
2396 {
2397 	if ( key == K_ESCAPE || key == K_ENTER )
2398 	{
2399 		s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
2400 		if ( s_savegame_menu.cursor < 0 )
2401 			s_savegame_menu.cursor = 0;
2402 	}
2403 	return Default_MenuKey( &s_loadgame_menu, key );
2404 }
2405 
M_Menu_LoadGame_f(void)2406 static void M_Menu_LoadGame_f (void)
2407 {
2408 	LoadGame_MenuInit();
2409 	M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
2410 }
2411 
2412 
2413 /*
2414 =============================================================================
2415 
2416 SAVEGAME MENU
2417 
2418 =============================================================================
2419 */
2420 static menuframework_s	s_savegame_menu;
2421 static menuaction_s		s_savegame_actions[MAX_SAVEGAMES];
2422 
SaveGameCallback(void * self)2423 static void SaveGameCallback( void *self )
2424 {
2425 	menuaction_s *a = ( menuaction_s * ) self;
2426 
2427 	Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
2428 	M_ForceMenuOff ();
2429 }
2430 
SaveGame_MenuDraw(void)2431 static void SaveGame_MenuDraw( void )
2432 {
2433 	M_Banner( "m_banner_save_game" );
2434 	Menu_AdjustCursor( &s_savegame_menu, 1 );
2435 	Menu_Draw( &s_savegame_menu );
2436 }
2437 
SaveGame_MenuInit(void)2438 static void SaveGame_MenuInit( void )
2439 {
2440 	int i;
2441 
2442 	s_savegame_menu.x = viddef.width / 2 - 120;
2443 	s_savegame_menu.y = viddef.height / 2 - 58;
2444 	s_savegame_menu.nitems = 0;
2445 
2446 	Create_Savestrings();
2447 
2448 	// don't include the autosave slot
2449 	for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
2450 	{
2451 		s_savegame_actions[i].generic.name = m_savestrings[i+1];
2452 		s_savegame_actions[i].generic.localdata[0] = i+1;
2453 		s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
2454 		s_savegame_actions[i].generic.callback = SaveGameCallback;
2455 
2456 		s_savegame_actions[i].generic.x = 0;
2457 		s_savegame_actions[i].generic.y = ( i ) * 10;
2458 
2459 		s_savegame_actions[i].generic.type = MTYPE_ACTION;
2460 
2461 		Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
2462 	}
2463 }
2464 
SaveGame_MenuKey(int key)2465 static const char *SaveGame_MenuKey( int key )
2466 {
2467 	if ( key == K_ENTER || key == K_ESCAPE )
2468 	{
2469 		s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
2470 		if ( s_loadgame_menu.cursor < 0 )
2471 			s_loadgame_menu.cursor = 0;
2472 	}
2473 	return Default_MenuKey( &s_savegame_menu, key );
2474 }
2475 
M_Menu_SaveGame_f(void)2476 static void M_Menu_SaveGame_f (void)
2477 {
2478 	if (!Com_ServerState())
2479 		return;		// not playing a game
2480 
2481 	SaveGame_MenuInit();
2482 	M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
2483 	Create_Savestrings ();
2484 }
2485 
2486 
2487 /*
2488 =============================================================================
2489 
2490 JOIN SERVER MENU
2491 
2492 =============================================================================
2493 */
2494 #define MAX_LOCAL_SERVERS 8
2495 
2496 static menuframework_s	s_joinserver_menu;
2497 static menuseparator_s	s_joinserver_server_title;
2498 static menuaction_s		s_joinserver_search_action;
2499 static menuaction_s		s_joinserver_address_book_action;
2500 static menuaction_s		s_joinserver_server_actions[MAX_LOCAL_SERVERS];
2501 
2502 int		m_num_servers;
2503 #define	NO_SERVER_STRING	"<no server>"
2504 
2505 // user readable information
2506 static char local_server_names[MAX_LOCAL_SERVERS][80];
2507 
2508 // network address
2509 static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
2510 
M_AddToServerList(netadr_t adr,char * info)2511 void M_AddToServerList (netadr_t adr, char *info)
2512 {
2513 	int		i;
2514 
2515 	if (m_num_servers == MAX_LOCAL_SERVERS)
2516 		return;
2517 	while ( *info == ' ' )
2518 		info++;
2519 
2520 	// ignore if duplicated
2521 	for (i=0 ; i<m_num_servers ; i++)
2522 		//if (!strcmp(info, local_server_names[i]))
2523 		if (NET_CompareAdr (&adr, &local_server_netadr[i]))
2524 			return;
2525 
2526 	local_server_netadr[m_num_servers] = adr;
2527 	snprintf (local_server_names[m_num_servers], sizeof(local_server_names[m_num_servers])-1, "%d. %s", m_num_servers+1, info);
2528 	m_num_servers++;
2529 }
2530 
2531 
JoinServerFunc(void * self)2532 static void JoinServerFunc( void *self )
2533 {
2534 	char	buffer[128];
2535 	int		index;
2536 
2537 	index = (int)(( menuaction_s * ) self - s_joinserver_server_actions);
2538 
2539 	if ( Q_stricmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
2540 		return;
2541 
2542 	if (index >= m_num_servers)
2543 		return;
2544 
2545 	Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (&local_server_netadr[index]));
2546 	Cbuf_AddText (buffer);
2547 	M_ForceMenuOff ();
2548 }
2549 
AddressBookFunc(void * self)2550 static void AddressBookFunc( void *self )
2551 {
2552 	M_Menu_AddressBook_f();
2553 }
2554 
2555 /*static void NullCursorDraw( void *self )
2556 {
2557 }*/
2558 
SearchLocalGames(void)2559 static void SearchLocalGames( void )
2560 {
2561 	int		i;
2562 
2563 	m_num_servers = 0;
2564 	for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
2565 		//strcpy (local_server_names[i], NO_SERVER_STRING);
2566 		sprintf (local_server_names[i], "%d. %s", i+1, NO_SERVER_STRING);
2567 
2568 	M_DrawTextBox( 8, 120 - 48, 36, 3 );
2569 	M_Print( 16 + 16, 120 - 48 + 8,  "Searching for local servers, this" );
2570 	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
2571 	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
2572 
2573 	// the text box won't show up unless we do a buffer swap
2574 	re.EndFrame();
2575 
2576 	// send out info packets
2577 	CL_PingServers_f();
2578 }
2579 
SearchLocalGamesFunc(void * self)2580 static void SearchLocalGamesFunc( void *self )
2581 {
2582 	SearchLocalGames();
2583 }
2584 
JoinServer_MenuInit(void)2585 static void JoinServer_MenuInit( void )
2586 {
2587 	int i;
2588 
2589 	s_joinserver_menu.x = (int)(viddef.width * 0.50f) - 120;
2590 	s_joinserver_menu.nitems = 0;
2591 
2592 	s_joinserver_address_book_action.generic.type	= MTYPE_ACTION;
2593 	s_joinserver_address_book_action.generic.name	= "address book";
2594 	s_joinserver_address_book_action.generic.flags	= QMF_LEFT_JUSTIFY;
2595 	s_joinserver_address_book_action.generic.x		= 0;
2596 	s_joinserver_address_book_action.generic.y		= 0;
2597 	s_joinserver_address_book_action.generic.callback = AddressBookFunc;
2598 
2599 	s_joinserver_search_action.generic.type = MTYPE_ACTION;
2600 	s_joinserver_search_action.generic.name	= "refresh server list";
2601 	s_joinserver_search_action.generic.flags	= QMF_LEFT_JUSTIFY;
2602 	s_joinserver_search_action.generic.x	= 0;
2603 	s_joinserver_search_action.generic.y	= 10;
2604 	s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
2605 	s_joinserver_search_action.generic.statusbar = "search for servers";
2606 
2607 	s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
2608 	s_joinserver_server_title.generic.name = "connect to...";
2609 	s_joinserver_server_title.generic.x    = 80;
2610 	s_joinserver_server_title.generic.y	   = 30;
2611 
2612 	for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
2613 	{
2614 		s_joinserver_server_actions[i].generic.type	= MTYPE_ACTION;
2615 		//strcpy (local_server_names[i], NO_SERVER_STRING);
2616 		sprintf (local_server_names[i], "%d. %s", i+1, NO_SERVER_STRING);
2617 		s_joinserver_server_actions[i].generic.name	= local_server_names[i];
2618 		s_joinserver_server_actions[i].generic.flags	= QMF_LEFT_JUSTIFY;
2619 		s_joinserver_server_actions[i].generic.x		= 0;
2620 		s_joinserver_server_actions[i].generic.y		= 40 + i*10;
2621 		s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
2622 		s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
2623 	}
2624 
2625 	Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
2626 	Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
2627 	Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
2628 
2629 	for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
2630 		Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
2631 
2632 	Menu_Center( &s_joinserver_menu );
2633 
2634 	SearchLocalGames();
2635 }
2636 
JoinServer_MenuDraw(void)2637 static void JoinServer_MenuDraw(void)
2638 {
2639 	M_Banner( "m_banner_join_server" );
2640 	Menu_Draw( &s_joinserver_menu );
2641 }
2642 
2643 
JoinServer_MenuKey(int key)2644 static const char *JoinServer_MenuKey( int key )
2645 {
2646 	//r1: join server shortcut keys
2647 	if (key >= '0' && key <= '9')
2648 	{
2649 		s_joinserver_menu.cursor = 2 + key - '0';
2650 		Menu_AdjustCursor (&s_joinserver_menu, 1);
2651 		Menu_SelectItem (&s_joinserver_menu);
2652 	}
2653 	return Default_MenuKey( &s_joinserver_menu, key );
2654 }
2655 
M_Menu_JoinServer_f(void)2656 static void M_Menu_JoinServer_f (void)
2657 {
2658 	JoinServer_MenuInit();
2659 	M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
2660 }
2661 
2662 
2663 /*
2664 =============================================================================
2665 
2666 START SERVER MENU
2667 
2668 =============================================================================
2669 */
2670 static menuframework_s s_startserver_menu;
2671 static char **mapnames;
2672 static int	  nummaps;
2673 
2674 static menuaction_s	s_startserver_start_action;
2675 static menuaction_s	s_startserver_dmoptions_action;
2676 
2677 static menufield_s	s_timelimit_field;
2678 static menufield_s	s_fraglimit_field;
2679 static menufield_s	s_maxclients_field;
2680 static menufield_s	s_hostname_field;
2681 static menulist_s	s_startmap_list;
2682 static menulist_s	s_rules_box;
2683 
DMOptionsFunc(void * self)2684 static void DMOptionsFunc( void *self )
2685 {
2686 	if (s_rules_box.curvalue == 1)
2687 		return;
2688 	M_Menu_DMOptions_f();
2689 }
2690 
RulesChangeFunc(void * self)2691 static void RulesChangeFunc ( void *self )
2692 {
2693 	// DM
2694 	if (s_rules_box.curvalue == 0)
2695 	{
2696 		s_maxclients_field.generic.statusbar = NULL;
2697 		s_startserver_dmoptions_action.generic.statusbar = NULL;
2698 	}
2699 	else if(s_rules_box.curvalue == 1)		// coop				// PGM
2700 	{
2701 		s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
2702 		if (atoi(s_maxclients_field.buffer) > 4)
2703 			strcpy( s_maxclients_field.buffer, "4" );
2704 		s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
2705 	}
2706 //=====
2707 //PGM
2708 	// ROGUE GAMES
2709 	else if(Developer_searchpath() == 2)
2710 	{
2711 		if (s_rules_box.curvalue == 2)			// tag
2712 		{
2713 			s_maxclients_field.generic.statusbar = NULL;
2714 			s_startserver_dmoptions_action.generic.statusbar = NULL;
2715 		}
2716 /*
2717 		else if(s_rules_box.curvalue == 3)		// deathball
2718 		{
2719 			s_maxclients_field.generic.statusbar = NULL;
2720 			s_startserver_dmoptions_action.generic.statusbar = NULL;
2721 		}
2722 */
2723 	}
2724 //PGM
2725 //=====
2726 }
2727 
StartServerActionFunc(void * self)2728 static void StartServerActionFunc( void *self )
2729 {
2730 	char	startmap[1024];
2731 	float	timelimit;
2732 	float	fraglimit;
2733 	float	maxclients;
2734 	char	*spot;
2735 
2736 	strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
2737 
2738 	maxclients  = (float)atof( s_maxclients_field.buffer );
2739 	timelimit	= (float)atof( s_timelimit_field.buffer );
2740 	fraglimit	= (float)atof( s_fraglimit_field.buffer );
2741 
2742 	Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
2743 	Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
2744 	Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
2745 	Cvar_Set("hostname", s_hostname_field.buffer );
2746 //	Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
2747 //	Cvar_SetValue ("coop", s_rules_box.curvalue );
2748 
2749 //PGM
2750 	if((s_rules_box.curvalue < 2) || (Developer_searchpath() != 2))
2751 	{
2752 		Cvar_SetValue ("deathmatch", (float)!s_rules_box.curvalue );
2753 		Cvar_SetValue ("coop", (float)s_rules_box.curvalue );
2754 		//Cvar_Set ("gamerules", "0" );
2755 	}
2756 	else
2757 	{
2758 		Cvar_Set ("deathmatch", "1" );	// deathmatch is always true for rogue games, right?
2759 		Cvar_Set ("coop", "0" );			// FIXME - this might need to depend on which game we're running
2760 		//Cvar_SetValue ("gamerules", (float)s_rules_box.curvalue );
2761 	}
2762 //PGM
2763 
2764 	spot = NULL;
2765 	if (s_rules_box.curvalue == 1)		// PGM
2766 	{
2767  		if(Q_stricmp(startmap, "bunk1") == 0)
2768   			spot = "start";
2769  		else if(Q_stricmp(startmap, "mintro") == 0)
2770   			spot = "start";
2771  		else if(Q_stricmp(startmap, "fact1") == 0)
2772   			spot = "start";
2773  		else if(Q_stricmp(startmap, "power1") == 0)
2774   			spot = "pstart";
2775  		else if(Q_stricmp(startmap, "biggun") == 0)
2776   			spot = "bstart";
2777  		else if(Q_stricmp(startmap, "hangar1") == 0)
2778   			spot = "unitstart";
2779  		else if(Q_stricmp(startmap, "city1") == 0)
2780   			spot = "unitstart";
2781  		else if(Q_stricmp(startmap, "boss1") == 0)
2782 			spot = "bosstart";
2783 	}
2784 
2785 	if (spot)
2786 	{
2787 		if (Com_ServerState())
2788 			Cbuf_AddText ("disconnect\n");
2789 		Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
2790 	}
2791 	else
2792 	{
2793 		Cbuf_AddText (va("killserver\nmap %s\n", startmap));
2794 	}
2795 
2796 	M_ForceMenuOff ();
2797 }
2798 
StartServer_MenuInit(void)2799 static void StartServer_MenuInit( void )
2800 {
2801 	static const char *dm_coop_names[] =
2802 	{
2803 		"deathmatch",
2804 		"cooperative",
2805 		0
2806 	};
2807 //=======
2808 //PGM
2809 	static const char *dm_coop_names_rogue[] =
2810 	{
2811 		"deathmatch",
2812 		"cooperative",
2813 		"tag",
2814 //		"deathball",
2815 		0
2816 	};
2817 //PGM
2818 //=======
2819 	char *buffer;
2820 	char  mapsname[1024];
2821 	char *s;
2822 	int length;
2823 	int i;
2824 	FILE *fp;
2825 
2826 	/*
2827 	** load the list of map names
2828 	*/
2829 	Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
2830 	if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
2831 	{
2832 		if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
2833 			Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
2834 	}
2835 	else
2836 	{
2837 #ifdef _WIN32
2838 		length = filelength( fileno( fp  ) );
2839 #else
2840 		fseek(fp, 0, SEEK_END);
2841 		length = ftell(fp);
2842 		fseek(fp, 0, SEEK_SET);
2843 #endif
2844 		buffer = malloc( length );
2845 		fread( buffer, length, 1, fp );
2846 	}
2847 
2848 	s = buffer;
2849 
2850 	i = 0;
2851 	while ( i < length )
2852 	{
2853 		if ( s[i] == '\r' )
2854 			nummaps++;
2855 		i++;
2856 	}
2857 
2858 	if ( nummaps == 0 )
2859 		Com_Error( ERR_DROP, "no maps in maps.lst\n" );
2860 
2861 	mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
2862 	memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
2863 
2864 	s = buffer;
2865 
2866 	for ( i = 0; i < nummaps; i++ )
2867 	{
2868     char  shortname[MAX_TOKEN_CHARS];
2869     char  longname[MAX_TOKEN_CHARS];
2870 		char  scratch[200];
2871 		int		j, l;
2872 
2873 		strcpy( shortname, COM_Parse( &s ) );
2874 		l = (int)strlen(shortname);
2875 		for (j=0 ; j<l ; j++)
2876 			shortname[j] = toupper(shortname[j]);
2877 		strcpy( longname, COM_Parse( &s ) );
2878 		Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
2879 
2880 		mapnames[i] = malloc( strlen( scratch ) + 1 );
2881 		strcpy( mapnames[i], scratch );
2882 	}
2883 	mapnames[nummaps] = 0;
2884 
2885 	if ( fp != 0 )
2886 	{
2887 		fp = 0;
2888 		free( buffer );
2889 	}
2890 	else
2891 	{
2892 		FS_FreeFile( buffer );
2893 	}
2894 
2895 	/*
2896 	** initialize the menu stuff
2897 	*/
2898 	s_startserver_menu.x = (int)(viddef.width * 0.50f);
2899 	s_startserver_menu.nitems = 0;
2900 
2901 	s_startmap_list.generic.type = MTYPE_SPINCONTROL;
2902 	s_startmap_list.generic.x	= 0;
2903 	s_startmap_list.generic.y	= 0;
2904 	s_startmap_list.generic.name	= "initial map";
2905 	s_startmap_list.itemnames = (const char **)mapnames;
2906 	s_startmap_list.curvalue = 0;
2907 
2908 	s_rules_box.generic.type = MTYPE_SPINCONTROL;
2909 	s_rules_box.generic.x	= 0;
2910 	s_rules_box.generic.y	= 20;
2911 	s_rules_box.generic.name	= "rules";
2912 
2913 //PGM - rogue games only available with rogue DLL.
2914 	if(Developer_searchpath() == 2)
2915 		s_rules_box.itemnames = dm_coop_names_rogue;
2916 	else
2917 		s_rules_box.itemnames = dm_coop_names;
2918 //PGM
2919 
2920 	if (Cvar_IntValue("coop"))
2921 		s_rules_box.curvalue = 1;
2922 	else
2923 		s_rules_box.curvalue = 0;
2924 	s_rules_box.generic.callback = RulesChangeFunc;
2925 
2926 	s_timelimit_field.generic.type = MTYPE_FIELD;
2927 	s_timelimit_field.generic.name = "time limit";
2928 	s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
2929 	s_timelimit_field.generic.x	= 0;
2930 	s_timelimit_field.generic.y	= 36;
2931 	s_timelimit_field.generic.statusbar = "0 = no limit";
2932 	s_timelimit_field.length = 3;
2933 	s_timelimit_field.visible_length = 3;
2934 	strncpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit"), sizeof(s_timelimit_field.buffer)-1);
2935 
2936 	s_fraglimit_field.generic.type = MTYPE_FIELD;
2937 	s_fraglimit_field.generic.name = "frag limit";
2938 	s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
2939 	s_fraglimit_field.generic.x	= 0;
2940 	s_fraglimit_field.generic.y	= 54;
2941 	s_fraglimit_field.generic.statusbar = "0 = no limit";
2942 	s_fraglimit_field.length = 3;
2943 	s_fraglimit_field.visible_length = 3;
2944 	strncpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit"), sizeof(s_fraglimit_field.buffer)-1);
2945 
2946 	/*
2947 	** maxclients determines the maximum number of players that can join
2948 	** the game.  If maxclients is only "1" then we should default the menu
2949 	** option to 8 players, otherwise use whatever its current value is.
2950 	** Clamping will be done when the server is actually started.
2951 	*/
2952 	s_maxclients_field.generic.type = MTYPE_FIELD;
2953 	s_maxclients_field.generic.name = "max players";
2954 	s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
2955 	s_maxclients_field.generic.x	= 0;
2956 	s_maxclients_field.generic.y	= 72;
2957 	s_maxclients_field.generic.statusbar = NULL;
2958 	s_maxclients_field.length = 3;
2959 	s_maxclients_field.visible_length = 3;
2960 	if ( Cvar_IntValue( "maxclients" ) == 1)
2961 		strcpy( s_maxclients_field.buffer, "8");
2962 	else
2963 		strncpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients"), sizeof(s_maxclients_field.buffer)-1);
2964 
2965 	s_hostname_field.generic.type = MTYPE_FIELD;
2966 	s_hostname_field.generic.name = "hostname";
2967 	s_hostname_field.generic.flags = 0;
2968 	s_hostname_field.generic.x	= 0;
2969 	s_hostname_field.generic.y	= 90;
2970 	s_hostname_field.generic.statusbar = NULL;
2971 	s_hostname_field.length = 12;
2972 	s_hostname_field.visible_length = 12;
2973 	strncpy( s_hostname_field.buffer, Cvar_VariableString("hostname"), sizeof(s_hostname_field.buffer));
2974 
2975 	s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
2976 	s_startserver_dmoptions_action.generic.name	= " deathmatch flags";
2977 	s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
2978 	s_startserver_dmoptions_action.generic.x	= 24;
2979 	s_startserver_dmoptions_action.generic.y	= 108;
2980 	s_startserver_dmoptions_action.generic.statusbar = NULL;
2981 	s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
2982 
2983 	s_startserver_start_action.generic.type = MTYPE_ACTION;
2984 	s_startserver_start_action.generic.name	= " begin";
2985 	s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
2986 	s_startserver_start_action.generic.x	= 24;
2987 	s_startserver_start_action.generic.y	= 128;
2988 	s_startserver_start_action.generic.callback = StartServerActionFunc;
2989 
2990 	Menu_AddItem( &s_startserver_menu, &s_startmap_list );
2991 	Menu_AddItem( &s_startserver_menu, &s_rules_box );
2992 	Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
2993 	Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
2994 	Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
2995 	Menu_AddItem( &s_startserver_menu, &s_hostname_field );
2996 	Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
2997 	Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
2998 
2999 	Menu_Center( &s_startserver_menu );
3000 
3001 	// call this now to set proper inital state
3002 	RulesChangeFunc ( NULL );
3003 }
3004 
StartServer_MenuDraw(void)3005 static void StartServer_MenuDraw(void)
3006 {
3007 	Menu_Draw( &s_startserver_menu );
3008 }
3009 
StartServer_MenuKey(int key)3010 static const char *StartServer_MenuKey( int key )
3011 {
3012 	if ( key == K_ESCAPE )
3013 	{
3014 		if ( mapnames )
3015 		{
3016 			int i;
3017 
3018 			for ( i = 0; i < nummaps; i++ )
3019 				free( mapnames[i] );
3020 			free( mapnames );
3021 		}
3022 		mapnames = 0;
3023 		nummaps = 0;
3024 	}
3025 
3026 	return Default_MenuKey( &s_startserver_menu, key );
3027 }
3028 
M_Menu_StartServer_f(void)3029 static void M_Menu_StartServer_f (void)
3030 {
3031 	StartServer_MenuInit();
3032 	M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
3033 }
3034 
3035 /*
3036 =============================================================================
3037 
3038 DMOPTIONS BOOK MENU
3039 
3040 =============================================================================
3041 */
3042 static char dmoptions_statusbar[128];
3043 
3044 static menuframework_s s_dmoptions_menu;
3045 
3046 static menulist_s	s_friendlyfire_box;
3047 static menulist_s	s_falls_box;
3048 static menulist_s	s_weapons_stay_box;
3049 static menulist_s	s_instant_powerups_box;
3050 static menulist_s	s_powerups_box;
3051 static menulist_s	s_health_box;
3052 static menulist_s	s_spawn_farthest_box;
3053 static menulist_s	s_teamplay_box;
3054 static menulist_s	s_samelevel_box;
3055 static menulist_s	s_force_respawn_box;
3056 static menulist_s	s_armor_box;
3057 static menulist_s	s_allow_exit_box;
3058 static menulist_s	s_infinite_ammo_box;
3059 static menulist_s	s_fixed_fov_box;
3060 static menulist_s	s_quad_drop_box;
3061 
3062 //ROGUE
3063 static menulist_s	s_no_mines_box;
3064 static menulist_s	s_no_nukes_box;
3065 static menulist_s	s_stack_double_box;
3066 static menulist_s	s_no_spheres_box;
3067 //ROGUE
3068 
DMFlagCallback(void * self)3069 static void DMFlagCallback( void *self )
3070 {
3071 	menulist_s *f = ( menulist_s * ) self;
3072 	int flags;
3073 	int bit = 0;
3074 
3075 	flags = Cvar_IntValue( "dmflags" );
3076 
3077 	if ( f == &s_friendlyfire_box )
3078 	{
3079 		if ( f->curvalue )
3080 			flags &= ~DF_NO_FRIENDLY_FIRE;
3081 		else
3082 			flags |= DF_NO_FRIENDLY_FIRE;
3083 		goto setvalue;
3084 	}
3085 	else if ( f == &s_falls_box )
3086 	{
3087 		if ( f->curvalue )
3088 			flags &= ~DF_NO_FALLING;
3089 		else
3090 			flags |= DF_NO_FALLING;
3091 		goto setvalue;
3092 	}
3093 	else if ( f == &s_weapons_stay_box )
3094 	{
3095 		bit = DF_WEAPONS_STAY;
3096 	}
3097 	else if ( f == &s_instant_powerups_box )
3098 	{
3099 		bit = DF_INSTANT_ITEMS;
3100 	}
3101 	else if ( f == &s_allow_exit_box )
3102 	{
3103 		bit = DF_ALLOW_EXIT;
3104 	}
3105 	else if ( f == &s_powerups_box )
3106 	{
3107 		if ( f->curvalue )
3108 			flags &= ~DF_NO_ITEMS;
3109 		else
3110 			flags |= DF_NO_ITEMS;
3111 		goto setvalue;
3112 	}
3113 	else if ( f == &s_health_box )
3114 	{
3115 		if ( f->curvalue )
3116 			flags &= ~DF_NO_HEALTH;
3117 		else
3118 			flags |= DF_NO_HEALTH;
3119 		goto setvalue;
3120 	}
3121 	else if ( f == &s_spawn_farthest_box )
3122 	{
3123 		bit = DF_SPAWN_FARTHEST;
3124 	}
3125 	else if ( f == &s_teamplay_box )
3126 	{
3127 		if ( f->curvalue == 1 )
3128 		{
3129 			flags |=  DF_SKINTEAMS;
3130 			flags &= ~DF_MODELTEAMS;
3131 		}
3132 		else if ( f->curvalue == 2 )
3133 		{
3134 			flags |=  DF_MODELTEAMS;
3135 			flags &= ~DF_SKINTEAMS;
3136 		}
3137 		else
3138 		{
3139 			flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
3140 		}
3141 
3142 		goto setvalue;
3143 	}
3144 	else if ( f == &s_samelevel_box )
3145 	{
3146 		bit = DF_SAME_LEVEL;
3147 	}
3148 	else if ( f == &s_force_respawn_box )
3149 	{
3150 		bit = DF_FORCE_RESPAWN;
3151 	}
3152 	else if ( f == &s_armor_box )
3153 	{
3154 		if ( f->curvalue )
3155 			flags &= ~DF_NO_ARMOR;
3156 		else
3157 			flags |= DF_NO_ARMOR;
3158 		goto setvalue;
3159 	}
3160 	else if ( f == &s_infinite_ammo_box )
3161 	{
3162 		bit = DF_INFINITE_AMMO;
3163 	}
3164 	else if ( f == &s_fixed_fov_box )
3165 	{
3166 		bit = DF_FIXED_FOV;
3167 	}
3168 	else if ( f == &s_quad_drop_box )
3169 	{
3170 		bit = DF_QUAD_DROP;
3171 	}
3172 
3173 //=======
3174 //ROGUE
3175 	else if (Developer_searchpath() == 2)
3176 	{
3177 		if ( f == &s_no_mines_box)
3178 		{
3179 			bit = DF_NO_MINES;
3180 		}
3181 		else if ( f == &s_no_nukes_box)
3182 		{
3183 			bit = DF_NO_NUKES;
3184 		}
3185 		else if ( f == &s_stack_double_box)
3186 		{
3187 			bit = DF_NO_STACK_DOUBLE;
3188 		}
3189 		else if ( f == &s_no_spheres_box)
3190 		{
3191 			bit = DF_NO_SPHERES;
3192 		}
3193 	}
3194 //ROGUE
3195 //=======
3196 
3197 	if ( f )
3198 	{
3199 		if ( f->curvalue == 0 )
3200 			flags &= ~bit;
3201 		else
3202 			flags |= bit;
3203 	}
3204 
3205 setvalue:
3206 	Cvar_SetValue ("dmflags", (float)flags);
3207 
3208 	Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
3209 
3210 }
3211 
DMOptions_MenuInit(void)3212 static void DMOptions_MenuInit( void )
3213 {
3214 	static const char *yes_no_names[] =
3215 	{
3216 		"no", "yes", 0
3217 	};
3218 	static const char *teamplay_names[] =
3219 	{
3220 		"disabled", "by skin", "by model", 0
3221 	};
3222 	int dmflags = Cvar_IntValue( "dmflags" );
3223 	int y = 0;
3224 
3225 	s_dmoptions_menu.x = (int)(viddef.width * 0.50f);
3226 	s_dmoptions_menu.nitems = 0;
3227 
3228 	s_falls_box.generic.type = MTYPE_SPINCONTROL;
3229 	s_falls_box.generic.x	= 0;
3230 	s_falls_box.generic.y	= y;
3231 	s_falls_box.generic.name	= "falling damage";
3232 	s_falls_box.generic.callback = DMFlagCallback;
3233 	s_falls_box.itemnames = yes_no_names;
3234 	s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
3235 
3236 	s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
3237 	s_weapons_stay_box.generic.x	= 0;
3238 	s_weapons_stay_box.generic.y	= y += 10;
3239 	s_weapons_stay_box.generic.name	= "weapons stay";
3240 	s_weapons_stay_box.generic.callback = DMFlagCallback;
3241 	s_weapons_stay_box.itemnames = yes_no_names;
3242 	s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
3243 
3244 	s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
3245 	s_instant_powerups_box.generic.x	= 0;
3246 	s_instant_powerups_box.generic.y	= y += 10;
3247 	s_instant_powerups_box.generic.name	= "instant powerups";
3248 	s_instant_powerups_box.generic.callback = DMFlagCallback;
3249 	s_instant_powerups_box.itemnames = yes_no_names;
3250 	s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
3251 
3252 	s_powerups_box.generic.type = MTYPE_SPINCONTROL;
3253 	s_powerups_box.generic.x	= 0;
3254 	s_powerups_box.generic.y	= y += 10;
3255 	s_powerups_box.generic.name	= "allow powerups";
3256 	s_powerups_box.generic.callback = DMFlagCallback;
3257 	s_powerups_box.itemnames = yes_no_names;
3258 	s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
3259 
3260 	s_health_box.generic.type = MTYPE_SPINCONTROL;
3261 	s_health_box.generic.x	= 0;
3262 	s_health_box.generic.y	= y += 10;
3263 	s_health_box.generic.callback = DMFlagCallback;
3264 	s_health_box.generic.name	= "allow health";
3265 	s_health_box.itemnames = yes_no_names;
3266 	s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
3267 
3268 	s_armor_box.generic.type = MTYPE_SPINCONTROL;
3269 	s_armor_box.generic.x	= 0;
3270 	s_armor_box.generic.y	= y += 10;
3271 	s_armor_box.generic.name	= "allow armor";
3272 	s_armor_box.generic.callback = DMFlagCallback;
3273 	s_armor_box.itemnames = yes_no_names;
3274 	s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
3275 
3276 	s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
3277 	s_spawn_farthest_box.generic.x	= 0;
3278 	s_spawn_farthest_box.generic.y	= y += 10;
3279 	s_spawn_farthest_box.generic.name	= "spawn farthest";
3280 	s_spawn_farthest_box.generic.callback = DMFlagCallback;
3281 	s_spawn_farthest_box.itemnames = yes_no_names;
3282 	s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
3283 
3284 	s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
3285 	s_samelevel_box.generic.x	= 0;
3286 	s_samelevel_box.generic.y	= y += 10;
3287 	s_samelevel_box.generic.name	= "same map";
3288 	s_samelevel_box.generic.callback = DMFlagCallback;
3289 	s_samelevel_box.itemnames = yes_no_names;
3290 	s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
3291 
3292 	s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
3293 	s_force_respawn_box.generic.x	= 0;
3294 	s_force_respawn_box.generic.y	= y += 10;
3295 	s_force_respawn_box.generic.name	= "force respawn";
3296 	s_force_respawn_box.generic.callback = DMFlagCallback;
3297 	s_force_respawn_box.itemnames = yes_no_names;
3298 	s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
3299 
3300 	s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
3301 	s_teamplay_box.generic.x	= 0;
3302 	s_teamplay_box.generic.y	= y += 10;
3303 	s_teamplay_box.generic.name	= "teamplay";
3304 	s_teamplay_box.generic.callback = DMFlagCallback;
3305 	s_teamplay_box.itemnames = teamplay_names;
3306 
3307 	s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
3308 	s_allow_exit_box.generic.x	= 0;
3309 	s_allow_exit_box.generic.y	= y += 10;
3310 	s_allow_exit_box.generic.name	= "allow exit";
3311 	s_allow_exit_box.generic.callback = DMFlagCallback;
3312 	s_allow_exit_box.itemnames = yes_no_names;
3313 	s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
3314 
3315 	s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
3316 	s_infinite_ammo_box.generic.x	= 0;
3317 	s_infinite_ammo_box.generic.y	= y += 10;
3318 	s_infinite_ammo_box.generic.name	= "infinite ammo";
3319 	s_infinite_ammo_box.generic.callback = DMFlagCallback;
3320 	s_infinite_ammo_box.itemnames = yes_no_names;
3321 	s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
3322 
3323 	s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
3324 	s_fixed_fov_box.generic.x	= 0;
3325 	s_fixed_fov_box.generic.y	= y += 10;
3326 	s_fixed_fov_box.generic.name	= "fixed FOV";
3327 	s_fixed_fov_box.generic.callback = DMFlagCallback;
3328 	s_fixed_fov_box.itemnames = yes_no_names;
3329 	s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
3330 
3331 	s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
3332 	s_quad_drop_box.generic.x	= 0;
3333 	s_quad_drop_box.generic.y	= y += 10;
3334 	s_quad_drop_box.generic.name	= "quad drop";
3335 	s_quad_drop_box.generic.callback = DMFlagCallback;
3336 	s_quad_drop_box.itemnames = yes_no_names;
3337 	s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
3338 
3339 	s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
3340 	s_friendlyfire_box.generic.x	= 0;
3341 	s_friendlyfire_box.generic.y	= y += 10;
3342 	s_friendlyfire_box.generic.name	= "friendly fire";
3343 	s_friendlyfire_box.generic.callback = DMFlagCallback;
3344 	s_friendlyfire_box.itemnames = yes_no_names;
3345 	s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
3346 
3347 //============
3348 //ROGUE
3349 	if(Developer_searchpath() == 2)
3350 	{
3351 		s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
3352 		s_no_mines_box.generic.x	= 0;
3353 		s_no_mines_box.generic.y	= y += 10;
3354 		s_no_mines_box.generic.name	= "remove mines";
3355 		s_no_mines_box.generic.callback = DMFlagCallback;
3356 		s_no_mines_box.itemnames = yes_no_names;
3357 		s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
3358 
3359 		s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
3360 		s_no_nukes_box.generic.x	= 0;
3361 		s_no_nukes_box.generic.y	= y += 10;
3362 		s_no_nukes_box.generic.name	= "remove nukes";
3363 		s_no_nukes_box.generic.callback = DMFlagCallback;
3364 		s_no_nukes_box.itemnames = yes_no_names;
3365 		s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
3366 
3367 		s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
3368 		s_stack_double_box.generic.x	= 0;
3369 		s_stack_double_box.generic.y	= y += 10;
3370 		s_stack_double_box.generic.name	= "2x/4x stacking off";
3371 		s_stack_double_box.generic.callback = DMFlagCallback;
3372 		s_stack_double_box.itemnames = yes_no_names;
3373 		s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
3374 
3375 		s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
3376 		s_no_spheres_box.generic.x	= 0;
3377 		s_no_spheres_box.generic.y	= y += 10;
3378 		s_no_spheres_box.generic.name	= "remove spheres";
3379 		s_no_spheres_box.generic.callback = DMFlagCallback;
3380 		s_no_spheres_box.itemnames = yes_no_names;
3381 		s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
3382 
3383 	}
3384 //ROGUE
3385 //============
3386 
3387 	Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
3388 	Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
3389 	Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
3390 	Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
3391 	Menu_AddItem( &s_dmoptions_menu, &s_health_box );
3392 	Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
3393 	Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
3394 	Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
3395 	Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
3396 	Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
3397 	Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
3398 	Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
3399 	Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
3400 	Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
3401 	Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
3402 
3403 //=======
3404 //ROGUE
3405 	if(Developer_searchpath() == 2)
3406 	{
3407 		Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
3408 		Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
3409 		Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
3410 		Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
3411 	}
3412 //ROGUE
3413 //=======
3414 
3415 	Menu_Center( &s_dmoptions_menu );
3416 
3417 	// set the original dmflags statusbar
3418 	DMFlagCallback( 0 );
3419 	Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
3420 }
3421 
DMOptions_MenuDraw(void)3422 static void DMOptions_MenuDraw(void)
3423 {
3424 	Menu_Draw( &s_dmoptions_menu );
3425 }
3426 
DMOptions_MenuKey(int key)3427 const char *DMOptions_MenuKey( int key )
3428 {
3429 	return Default_MenuKey( &s_dmoptions_menu, key );
3430 }
3431 
M_Menu_DMOptions_f(void)3432 static void M_Menu_DMOptions_f (void)
3433 {
3434 	DMOptions_MenuInit();
3435 	M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
3436 }
3437 
3438 /*
3439 =============================================================================
3440 
3441 DOWNLOADOPTIONS BOOK MENU
3442 
3443 =============================================================================
3444 */
3445 static menuframework_s s_downloadoptions_menu;
3446 
3447 static menuseparator_s	s_download_title;
3448 static menulist_s	s_allow_download_box;
3449 static menulist_s	s_allow_download_maps_box;
3450 static menulist_s	s_allow_download_models_box;
3451 static menulist_s	s_allow_download_players_box;
3452 static menulist_s	s_allow_download_sounds_box;
3453 
DownloadCallback(void * self)3454 static void DownloadCallback( void *self )
3455 {
3456 	menulist_s *f = ( menulist_s * ) self;
3457 
3458 	if (f == &s_allow_download_box)
3459 	{
3460 		Cvar_SetValue("allow_download", (float)f->curvalue);
3461 	}
3462 
3463 	else if (f == &s_allow_download_maps_box)
3464 	{
3465 		Cvar_SetValue("allow_download_maps", (float)f->curvalue);
3466 	}
3467 
3468 	else if (f == &s_allow_download_models_box)
3469 	{
3470 		Cvar_SetValue("allow_download_models", (float)f->curvalue);
3471 	}
3472 
3473 	else if (f == &s_allow_download_players_box)
3474 	{
3475 		Cvar_SetValue("allow_download_players", (float)f->curvalue);
3476 	}
3477 
3478 	else if (f == &s_allow_download_sounds_box)
3479 	{
3480 		Cvar_SetValue("allow_download_sounds", (float)f->curvalue);
3481 	}
3482 }
3483 
DownloadOptions_MenuInit(void)3484 static void DownloadOptions_MenuInit( void )
3485 {
3486 	static const char *yes_no_names[] =
3487 	{
3488 		"no", "yes", 0
3489 	};
3490 	int y = 0;
3491 
3492 	s_downloadoptions_menu.x = (int)(viddef.width * 0.50f);
3493 	s_downloadoptions_menu.nitems = 0;
3494 
3495 	s_download_title.generic.type = MTYPE_SEPARATOR;
3496 	s_download_title.generic.name = "Download Options";
3497 	s_download_title.generic.x    = 48;
3498 	s_download_title.generic.y	 = y;
3499 
3500 	s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
3501 	s_allow_download_box.generic.x	= 0;
3502 	s_allow_download_box.generic.y	= y += 20;
3503 	s_allow_download_box.generic.name	= "allow downloading";
3504 	s_allow_download_box.generic.callback = DownloadCallback;
3505 	s_allow_download_box.itemnames = yes_no_names;
3506 	s_allow_download_box.curvalue = (Cvar_IntValue("allow_download") != 0);
3507 
3508 	s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
3509 	s_allow_download_maps_box.generic.x	= 0;
3510 	s_allow_download_maps_box.generic.y	= y += 20;
3511 	s_allow_download_maps_box.generic.name	= "maps";
3512 	s_allow_download_maps_box.generic.callback = DownloadCallback;
3513 	s_allow_download_maps_box.itemnames = yes_no_names;
3514 	s_allow_download_maps_box.curvalue = (Cvar_IntValue("allow_download_maps") != 0);
3515 
3516 	s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
3517 	s_allow_download_players_box.generic.x	= 0;
3518 	s_allow_download_players_box.generic.y	= y += 10;
3519 	s_allow_download_players_box.generic.name	= "player models/skins";
3520 	s_allow_download_players_box.generic.callback = DownloadCallback;
3521 	s_allow_download_players_box.itemnames = yes_no_names;
3522 	s_allow_download_players_box.curvalue = (Cvar_IntValue("allow_download_players") != 0);
3523 
3524 	s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
3525 	s_allow_download_models_box.generic.x	= 0;
3526 	s_allow_download_models_box.generic.y	= y += 10;
3527 	s_allow_download_models_box.generic.name	= "models";
3528 	s_allow_download_models_box.generic.callback = DownloadCallback;
3529 	s_allow_download_models_box.itemnames = yes_no_names;
3530 	s_allow_download_models_box.curvalue = (Cvar_IntValue("allow_download_models") != 0);
3531 
3532 	s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
3533 	s_allow_download_sounds_box.generic.x	= 0;
3534 	s_allow_download_sounds_box.generic.y	= y += 10;
3535 	s_allow_download_sounds_box.generic.name	= "sounds";
3536 	s_allow_download_sounds_box.generic.callback = DownloadCallback;
3537 	s_allow_download_sounds_box.itemnames = yes_no_names;
3538 	s_allow_download_sounds_box.curvalue = (Cvar_IntValue("allow_download_sounds") != 0);
3539 
3540 	Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
3541 	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
3542 	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
3543 	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
3544 	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
3545 	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
3546 
3547 	Menu_Center( &s_downloadoptions_menu );
3548 
3549 	// skip over title
3550 	if (s_downloadoptions_menu.cursor == 0)
3551 		s_downloadoptions_menu.cursor = 1;
3552 }
3553 
DownloadOptions_MenuDraw(void)3554 static void DownloadOptions_MenuDraw(void)
3555 {
3556 	Menu_Draw( &s_downloadoptions_menu );
3557 }
3558 
DownloadOptions_MenuKey(int key)3559 static const char *DownloadOptions_MenuKey( int key )
3560 {
3561 	return Default_MenuKey( &s_downloadoptions_menu, key );
3562 }
3563 
M_Menu_DownloadOptions_f(void)3564 static void M_Menu_DownloadOptions_f (void)
3565 {
3566 	DownloadOptions_MenuInit();
3567 	M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
3568 }
3569 /*
3570 =============================================================================
3571 
3572 ADDRESS BOOK MENU
3573 
3574 =============================================================================
3575 */
3576 #define NUM_ADDRESSBOOK_ENTRIES 9
3577 
3578 static menuframework_s	s_addressbook_menu;
3579 static menufield_s		s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
3580 
AddressBook_MenuInit(void)3581 static void AddressBook_MenuInit( void )
3582 {
3583 	int i;
3584 
3585 	s_addressbook_menu.x = viddef.width / 2 - 142;
3586 	s_addressbook_menu.y = viddef.height / 2 - 58;
3587 	s_addressbook_menu.nitems = 0;
3588 
3589 	for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
3590 	{
3591 		cvar_t *adr;
3592 		char buffer[16];
3593 
3594 		Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
3595 
3596 		adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
3597 
3598 		s_addressbook_fields[i].generic.type = MTYPE_FIELD;
3599 		s_addressbook_fields[i].generic.name = 0;
3600 		s_addressbook_fields[i].generic.callback = 0;
3601 		s_addressbook_fields[i].generic.x		= 0;
3602 		s_addressbook_fields[i].generic.y		= i * 18 + 0;
3603 		s_addressbook_fields[i].generic.localdata[0] = i;
3604 		s_addressbook_fields[i].cursor			= 0;
3605 		s_addressbook_fields[i].length			= 60;
3606 		s_addressbook_fields[i].visible_length	= 30;
3607 
3608 		strncpy( s_addressbook_fields[i].buffer, adr->string, sizeof (s_addressbook_fields[i].buffer));
3609 
3610 		Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
3611 	}
3612 }
3613 
AddressBook_MenuKey(int key)3614 const char *AddressBook_MenuKey( int key )
3615 {
3616 	if ( key == K_ESCAPE )
3617 	{
3618 		int index;
3619 		char buffer[16];
3620 
3621 		for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
3622 		{
3623 			Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
3624 			Cvar_Set( buffer, s_addressbook_fields[index].buffer );
3625 		}
3626 	}
3627 	return Default_MenuKey( &s_addressbook_menu, key );
3628 }
3629 
AddressBook_MenuDraw(void)3630 static void AddressBook_MenuDraw(void)
3631 {
3632 	M_Banner( "m_banner_addressbook" );
3633 	Menu_Draw( &s_addressbook_menu );
3634 }
3635 
M_Menu_AddressBook_f(void)3636 static void M_Menu_AddressBook_f(void)
3637 {
3638 	AddressBook_MenuInit();
3639 	M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
3640 }
3641 
3642 /*
3643 =============================================================================
3644 
3645 PLAYER CONFIG MENU
3646 
3647 =============================================================================
3648 */
3649 static menuframework_s	s_player_config_menu;
3650 static menufield_s		s_player_name_field;
3651 static menulist_s		s_player_model_box;
3652 static menulist_s		s_player_skin_box;
3653 static menulist_s		s_player_handedness_box;
3654 static menulist_s		s_player_rate_box;
3655 static menuseparator_s	s_player_skin_title;
3656 static menuseparator_s	s_player_model_title;
3657 static menuseparator_s	s_player_hand_title;
3658 static menuseparator_s	s_player_rate_title;
3659 static menuaction_s		s_player_download_action;
3660 
3661 #define MAX_DISPLAYNAME 16
3662 #define MAX_PLAYERMODELS 1024
3663 
3664 typedef struct
3665 {
3666 	int		nskins;
3667 	char	**skindisplaynames;
3668 	char	displayname[MAX_DISPLAYNAME];
3669 	char	directory[MAX_QPATH];
3670 } playermodelinfo_s;
3671 
3672 static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
3673 static char *s_pmnames[MAX_PLAYERMODELS];
3674 static int s_numplayermodels;
3675 
3676 static int rate_tbl[] = { 2500, 3200, 4300, 5000, 15000, 0 };
3677 static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "56.6 Modem", "ISDN",
3678 	"Cable/DSL/LAN", "User defined", 0 };
3679 
DownloadOptionsFunc(void * self)3680 static void DownloadOptionsFunc( void *self )
3681 {
3682 	M_Menu_DownloadOptions_f();
3683 }
3684 
HandednessCallback(void * unused)3685 static void HandednessCallback( void *unused )
3686 {
3687 	Cvar_SetValue( "hand", (float)s_player_handedness_box.curvalue );
3688 }
3689 
RateCallback(void * unused)3690 static void RateCallback( void *unused )
3691 {
3692 	if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
3693 		Cvar_SetValue( "rate", (float)rate_tbl[s_player_rate_box.curvalue] );
3694 }
3695 
ModelCallback(void * unused)3696 static void ModelCallback( void *unused )
3697 {
3698 	s_player_skin_box.itemnames = (const char **)s_pmi[s_player_model_box.curvalue].skindisplaynames;
3699 	s_player_skin_box.curvalue = 0;
3700 }
3701 
FreeFileList(char ** list,int n)3702 static void FreeFileList( char **list, int n )
3703 {
3704 	int i;
3705 
3706 	for ( i = 0; i < n; i++ )
3707 	{
3708 		if ( list[i] )
3709 		{
3710 			free( list[i] );
3711 			list[i] = 0;
3712 		}
3713 	}
3714 	free( list );
3715 }
3716 
IconOfSkinExists(char * skin,char ** pcxfiles,int npcxfiles)3717 static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
3718 {
3719 	int i;
3720 	char scratch[1024];
3721 
3722 	Q_strncpy( scratch, skin, sizeof(scratch)-7);
3723 	*strrchr( scratch, '.' ) = 0;
3724 	strcat( scratch, "_i.pcx" );
3725 
3726 	for ( i = 0; i < npcxfiles; i++ )
3727 	{
3728 		if ( strcmp( pcxfiles[i], scratch ) == 0 )
3729 			return true;
3730 	}
3731 
3732 	return false;
3733 }
3734 
3735 extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
PlayerConfig_ScanDirectories(void)3736 static qboolean PlayerConfig_ScanDirectories( void )
3737 {
3738 	char findname[1024];
3739 	char scratch[1024];
3740 	int ndirs = 0, npms = 0;
3741 	char **dirnames;
3742 	char *path = NULL;
3743 	int i;
3744 
3745 	s_numplayermodels = 0;
3746 
3747 	/*
3748 	** get a list of directories
3749 	*/
3750 	do
3751 	{
3752 		path = FS_NextPath( path );
3753 		Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
3754 
3755 		if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
3756 			break;
3757 	} while ( path );
3758 
3759 	if ( !dirnames )
3760 		return false;
3761 
3762 	/*
3763 	** go through the subdirectories
3764 	*/
3765 	npms = ndirs;
3766 	if ( npms > MAX_PLAYERMODELS )
3767 		npms = MAX_PLAYERMODELS;
3768 
3769 	//jesus christ this is fucking ugly
3770 	for ( i = 0; i < npms; i++ )
3771 	{
3772 		int k, s;
3773 		char *a, *b, *c;
3774 		char **pcxnames;
3775 		char **skinnames;
3776 		int npcxfiles;
3777 		int nskins = 0;
3778 
3779 		if ( dirnames[i] == 0 )
3780 			continue;
3781 
3782 		// verify the existence of tris.md2
3783 		Q_strncpy( scratch, dirnames[i], sizeof(scratch)-10);
3784 		strcat( scratch, "/tris.md2" );
3785 
3786 		if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
3787 		{
3788 			free( dirnames[i] );
3789 			dirnames[i] = 0;
3790 			Sys_FindClose();
3791 			continue;
3792 		}
3793 		Sys_FindClose();
3794 
3795 		// verify the existence of at least one pcx skin
3796 		Q_strncpy( scratch, dirnames[i], sizeof(scratch)-10);
3797 		strcat( scratch, "/*.pcx" );
3798 		pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
3799 
3800 		if ( !pcxnames )
3801 		{
3802 			free( dirnames[i] );
3803 			dirnames[i] = 0;
3804 			continue;
3805 		}
3806 
3807 		// count valid skins, which consist of a skin with a matching "_i" icon
3808 		for ( k = 0; k < npcxfiles-1; k++ )
3809 		{
3810 			if ( !strstr( pcxnames[k], "_i.pcx" ) )
3811 			{
3812 				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
3813 				{
3814 					nskins++;
3815 				}
3816 			}
3817 		}
3818 
3819 		if ( !nskins )
3820 			continue;
3821 
3822 		skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
3823 		memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
3824 
3825 		// copy the valid skins
3826 		for ( s = 0, k = 0; k < npcxfiles-1; k++ )
3827 		{
3828 			char *a, *b, *c;
3829 
3830 			if ( !strstr( pcxnames[k], "_i.pcx" ) )
3831 			{
3832 				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
3833 				{
3834 					a = strrchr( pcxnames[k], '/' );
3835 					b = strrchr( pcxnames[k], '\\' );
3836 
3837 					if ( a > b )
3838 						c = a;
3839 					else
3840 						c = b;
3841 
3842 					Q_strncpy( scratch, c + 1, sizeof(scratch)-1);
3843 
3844 					if ( strrchr( scratch, '.' ) )
3845 						*strrchr( scratch, '.' ) = 0;
3846 
3847 					skinnames[s] = strdup( scratch );
3848 					s++;
3849 				}
3850 			}
3851 		}
3852 
3853 		// at this point we have a valid player model
3854 		s_pmi[s_numplayermodels].nskins = nskins;
3855 		s_pmi[s_numplayermodels].skindisplaynames = skinnames;
3856 
3857 		// make short name for the model
3858 		a = strrchr( dirnames[i], '/' );
3859 		b = strrchr( dirnames[i], '\\' );
3860 
3861 		if ( a > b )
3862 			c = a;
3863 		else
3864 			c = b;
3865 
3866 		strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1);
3867 		strncpy( s_pmi[s_numplayermodels].directory, c + 1, MAX_QPATH-1);
3868 
3869 		FreeFileList( pcxnames, npcxfiles );
3870 
3871 		if (++s_numplayermodels == MAX_PLAYERMODELS)
3872 			break;
3873 	}
3874 	if ( dirnames )
3875 		FreeFileList( dirnames, ndirs );
3876 
3877 	//shut up
3878 	return false;
3879 }
3880 
pmicmpfnc(const void * _a,const void * _b)3881 static int EXPORT pmicmpfnc( const void *_a, const void *_b )
3882 {
3883 	const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
3884 	const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
3885 
3886 	/*
3887 	** sort by male, female, then alphabetical
3888 	*/
3889 	if ( strcmp( a->directory, "male" ) == 0 )
3890 		return -1;
3891 	else if ( strcmp( b->directory, "male" ) == 0 )
3892 		return 1;
3893 
3894 	if ( strcmp( a->directory, "female" ) == 0 )
3895 		return -1;
3896 	else if ( strcmp( b->directory, "female" ) == 0 )
3897 		return 1;
3898 
3899 	return strcmp( a->directory, b->directory );
3900 }
3901 
3902 
PlayerConfig_MenuInit(void)3903 static qboolean PlayerConfig_MenuInit( void )
3904 {
3905 	//extern cvar_t *name;
3906 	//extern cvar_t *skin;
3907 
3908 	char currentdirectory[1024];
3909 	char currentskin[1024];
3910 	int i = 0;
3911 	int	hand;
3912 
3913 	int currentdirectoryindex = 0;
3914 	int currentskinindex = 0;
3915 
3916 	//cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
3917 
3918 	static const char *handedness[] = { "right", "left", "center", 0 };
3919 
3920 	PlayerConfig_ScanDirectories();
3921 
3922 	if (s_numplayermodels == 0)
3923 		return false;
3924 
3925 	hand = Cvar_IntValue ("hand");
3926 
3927 	if ( hand < 0 || hand > 2)
3928 		Cvar_Set( "hand", "0" );
3929 
3930 	//r1: BUFFER OVERFLOW WAS HERE
3931 	Q_strncpy( currentdirectory, Cvar_VariableString ("skin"), sizeof(currentdirectory)-1);
3932 
3933 	if ( strchr( currentdirectory, '/' ) )
3934 	{
3935 		strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
3936 		*strchr( currentdirectory, '/' ) = 0;
3937 	}
3938 	else if ( strchr( currentdirectory, '\\' ) )
3939 	{
3940 		strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
3941 		*strchr( currentdirectory, '\\' ) = 0;
3942 	}
3943 	else
3944 	{
3945 		strcpy( currentdirectory, "male" );
3946 		strcpy( currentskin, "grunt" );
3947 	}
3948 
3949 	qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), (int (EXPORT *)(const void *, const void *))pmicmpfnc );
3950 
3951 	memset( s_pmnames, 0, sizeof( s_pmnames ) );
3952 	for ( i = 0; i < s_numplayermodels; i++ )
3953 	{
3954 		s_pmnames[i] = s_pmi[i].displayname;
3955 		if ( Q_stricmp( s_pmi[i].directory, currentdirectory ) == 0 )
3956 		{
3957 			int j;
3958 
3959 			currentdirectoryindex = i;
3960 
3961 			for ( j = 0; j < s_pmi[i].nskins; j++ )
3962 			{
3963 				if ( Q_stricmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
3964 				{
3965 					currentskinindex = j;
3966 					break;
3967 				}
3968 			}
3969 		}
3970 	}
3971 
3972 	s_player_config_menu.x = viddef.width / 2 - 95;
3973 	s_player_config_menu.y = viddef.height / 2 - 97;
3974 	s_player_config_menu.nitems = 0;
3975 
3976 	s_player_name_field.generic.type = MTYPE_FIELD;
3977 	s_player_name_field.generic.name = "name";
3978 	s_player_name_field.generic.callback = 0;
3979 	s_player_name_field.generic.x		= 0;
3980 	s_player_name_field.generic.y		= 0;
3981 	s_player_name_field.length	= 20;
3982 	s_player_name_field.visible_length = 20;
3983 	strncpy( s_player_name_field.buffer, Cvar_VariableString ("name"), sizeof(s_player_name_field.buffer)-1);
3984 	s_player_name_field.cursor = (int)strlen( s_player_name_field.buffer );
3985 
3986 	s_player_model_title.generic.type = MTYPE_SEPARATOR;
3987 	s_player_model_title.generic.name = "model";
3988 	s_player_model_title.generic.x    = -8;
3989 	s_player_model_title.generic.y	 = 60;
3990 
3991 	s_player_model_box.generic.type = MTYPE_SPINCONTROL;
3992 	s_player_model_box.generic.x	= -56;
3993 	s_player_model_box.generic.y	= 70;
3994 	s_player_model_box.generic.callback = ModelCallback;
3995 	s_player_model_box.generic.cursor_offset = -48;
3996 	s_player_model_box.curvalue = currentdirectoryindex;
3997 	s_player_model_box.itemnames = (const char **)s_pmnames;
3998 
3999 	s_player_skin_title.generic.type = MTYPE_SEPARATOR;
4000 	s_player_skin_title.generic.name = "skin";
4001 	s_player_skin_title.generic.x    = -16;
4002 	s_player_skin_title.generic.y	 = 84;
4003 
4004 	s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
4005 	s_player_skin_box.generic.x	= -56;
4006 	s_player_skin_box.generic.y	= 94;
4007 	s_player_skin_box.generic.name	= 0;
4008 	s_player_skin_box.generic.callback = 0;
4009 	s_player_skin_box.generic.cursor_offset = -48;
4010 	s_player_skin_box.curvalue = currentskinindex;
4011 	s_player_skin_box.itemnames = (const char **)s_pmi[currentdirectoryindex].skindisplaynames;
4012 
4013 	s_player_hand_title.generic.type = MTYPE_SEPARATOR;
4014 	s_player_hand_title.generic.name = "handedness";
4015 	s_player_hand_title.generic.x    = 32;
4016 	s_player_hand_title.generic.y	 = 108;
4017 
4018 	s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
4019 	s_player_handedness_box.generic.x	= -56;
4020 	s_player_handedness_box.generic.y	= 118;
4021 	s_player_handedness_box.generic.name	= 0;
4022 	s_player_handedness_box.generic.cursor_offset = -48;
4023 	s_player_handedness_box.generic.callback = HandednessCallback;
4024 	s_player_handedness_box.curvalue = Cvar_IntValue( "hand" );
4025 	s_player_handedness_box.itemnames = handedness;
4026 
4027 	for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
4028 		if (Cvar_IntValue("rate") == rate_tbl[i])
4029 			break;
4030 
4031 	s_player_rate_title.generic.type = MTYPE_SEPARATOR;
4032 	s_player_rate_title.generic.name = "connect speed";
4033 	s_player_rate_title.generic.x    = 56;
4034 	s_player_rate_title.generic.y	 = 156;
4035 
4036 	s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
4037 	s_player_rate_box.generic.x	= -56;
4038 	s_player_rate_box.generic.y	= 166;
4039 	s_player_rate_box.generic.name	= 0;
4040 	s_player_rate_box.generic.cursor_offset = -48;
4041 	s_player_rate_box.generic.callback = RateCallback;
4042 	s_player_rate_box.curvalue = i;
4043 	s_player_rate_box.itemnames = rate_names;
4044 
4045 	s_player_download_action.generic.type = MTYPE_ACTION;
4046 	s_player_download_action.generic.name	= "download options";
4047 	s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
4048 	s_player_download_action.generic.x	= -24;
4049 	s_player_download_action.generic.y	= 186;
4050 	s_player_download_action.generic.statusbar = NULL;
4051 	s_player_download_action.generic.callback = DownloadOptionsFunc;
4052 
4053 	Menu_AddItem( &s_player_config_menu, &s_player_name_field );
4054 	Menu_AddItem( &s_player_config_menu, &s_player_model_title );
4055 	Menu_AddItem( &s_player_config_menu, &s_player_model_box );
4056 	if ( s_player_skin_box.itemnames )
4057 	{
4058 		Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
4059 		Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
4060 	}
4061 	Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
4062 	Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
4063 	Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
4064 	Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
4065 	Menu_AddItem( &s_player_config_menu, &s_player_download_action );
4066 
4067 	return true;
4068 }
4069 
4070 extern float CalcFov( float fov_x, int w, int h );
PlayerConfig_MenuDraw(void)4071 static void PlayerConfig_MenuDraw( void )
4072 {
4073 	refdef_t refdef;
4074 	char scratch[MAX_QPATH];
4075 
4076 	memset( &refdef, 0, sizeof( refdef ) );
4077 
4078 	refdef.x = viddef.width / 2;
4079 	refdef.y = viddef.height / 2 - 72;
4080 	refdef.width = 144;
4081 	refdef.height = 168;
4082 	refdef.fov_x = 40;
4083 	refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
4084 	refdef.time = cls.realtime*0.001f;
4085 
4086 	if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
4087 	{
4088 		static int yaw;
4089 		//int maxframe = 29;
4090 		entity_t entity;
4091 
4092 		memset( &entity, 0, sizeof( entity ) );
4093 
4094 		Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
4095 		entity.model = re.RegisterModel( scratch );
4096 		Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
4097 		entity.skin = re.RegisterSkin( scratch );
4098 		entity.flags = RF_FULLBRIGHT;
4099 		entity.origin[0] = 80;
4100 		entity.origin[1] = 0;
4101 		entity.origin[2] = 0;
4102 		FastVectorCopy( entity.origin, entity.oldorigin );
4103 		entity.frame = 0;
4104 		entity.oldframe = 0;
4105 		entity.backlerp = 0.0;
4106 		entity.angles[1] = (float)yaw;
4107 		yaw++;
4108 		if ( ++yaw > 360 )
4109 			yaw -= 360;
4110 
4111 		refdef.areabits = 0;
4112 		refdef.num_entities = 1;
4113 		refdef.entities = &entity;
4114 		refdef.lightstyles = 0;
4115 		refdef.rdflags = RDF_NOWORLDMODEL;
4116 
4117 		Menu_Draw( &s_player_config_menu );
4118 
4119 		M_DrawTextBox( (int)(( refdef.x ) * ( 320.0F / viddef.width ) - 8), (int)(( viddef.height / 2 ) * ( 240.0F / viddef.height) - 77), refdef.width / 8, refdef.height / 8 );
4120 		refdef.height += 4;
4121 
4122 		re.RenderFrame( &refdef );
4123 
4124 		Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx",
4125 			s_pmi[s_player_model_box.curvalue].directory,
4126 			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
4127 		re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
4128 	}
4129 }
4130 
PlayerConfig_MenuKey(int key)4131 static const char *PlayerConfig_MenuKey (int key)
4132 {
4133 	int i;
4134 
4135 	if ( key == K_ESCAPE )
4136 	{
4137 		char scratch[1024];
4138 
4139 		Cvar_Set( "name", s_player_name_field.buffer );
4140 
4141 		Com_sprintf( scratch, sizeof( scratch ), "%s/%s",
4142 			s_pmi[s_player_model_box.curvalue].directory,
4143 			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
4144 
4145 		Cvar_Set( "skin", scratch );
4146 
4147 		for ( i = 0; i < s_numplayermodels; i++ )
4148 		{
4149 			int j;
4150 
4151 			for ( j = 0; j < s_pmi[i].nskins; j++ )
4152 			{
4153 				if ( s_pmi[i].skindisplaynames[j] )
4154 					free( s_pmi[i].skindisplaynames[j] );
4155 				s_pmi[i].skindisplaynames[j] = 0;
4156 			}
4157 			free( s_pmi[i].skindisplaynames );
4158 			s_pmi[i].skindisplaynames = 0;
4159 			s_pmi[i].nskins = 0;
4160 		}
4161 	}
4162 	return Default_MenuKey( &s_player_config_menu, key );
4163 }
4164 
4165 
M_Menu_PlayerConfig_f(void)4166 static void M_Menu_PlayerConfig_f (void)
4167 {
4168 	if (!PlayerConfig_MenuInit())
4169 	{
4170 		Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
4171 		return;
4172 	}
4173 	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
4174 	M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
4175 }
4176 
4177 
4178 /*
4179 =======================================================================
4180 
4181 GALLERY MENU
4182 
4183 =======================================================================
4184 */
4185 
M_Menu_Quit_f(void)4186 static void M_Menu_Quit_f (void)
4187 {
4188 	CL_Quit_f ();
4189 }
4190 
4191 
4192 
4193 //=============================================================================
4194 /* Menu Subsystem */
4195 
4196 
4197 /*
4198 =================
4199 M_Init
4200 =================
4201 */
M_Init(void)4202 void M_Init (void)
4203 {
4204 	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
4205 	Cmd_AddCommand ("menu_game", M_Menu_Game_f);
4206 		Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
4207 		Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
4208 		Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
4209 			Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
4210 		Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
4211 			Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
4212 		Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
4213 			Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
4214 		Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
4215 	Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
4216 	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
4217 	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
4218 		Cmd_AddCommand ("menu_r1q2", M_Menu_R1Q2_f);
4219 		Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
4220 	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
4221 }
4222 
4223 
4224 /*
4225 =================
4226 M_Draw
4227 =================
4228 */
M_Draw(void)4229 void M_Draw (void)
4230 {
4231 	if (cls.key_dest != key_menu)
4232 		return;
4233 
4234 	// repaint everything next frame
4235 	SCR_DirtyScreen ();
4236 
4237 	// dim everything behind it down
4238 #ifdef CINEMATICS
4239 	if (cl.cinematictime > 0)
4240 		re.DrawFill (0,0,viddef.width, viddef.height, 0);
4241 	else
4242 #endif
4243 		re.DrawFadeScreen ();
4244 
4245 	m_drawfunc ();
4246 
4247 	// delay playing the enter sound until after the
4248 	// menu has been drawn, to avoid delay while
4249 	// caching images
4250 	if (m_entersound)
4251 	{
4252 		S_StartLocalSound( menu_in_sound );
4253 		m_entersound = false;
4254 	}
4255 }
4256 
4257 
4258 /*
4259 =================
4260 M_Keydown
4261 =================
4262 */
M_Keydown(int key)4263 void M_Keydown (int key)
4264 {
4265 	const char *s;
4266 
4267 	if (m_keyfunc)
4268 		if ( ( s = m_keyfunc( key ) ) != 0 )
4269 			S_StartLocalSound( ( char * ) s );
4270 }
4271 
4272 
4273