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