Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ui_menu.c (10939B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 /*
     24 =======================================================================
     25 
     26 MAIN MENU
     27 
     28 =======================================================================
     29 */
     30 
     31 
     32 #include "ui_local.h"
     33 
     34 
     35 #define ID_SINGLEPLAYER			10
     36 #define ID_MULTIPLAYER			11
     37 #define ID_SETUP				12
     38 #define ID_DEMOS				13
     39 #define ID_CINEMATICS			14
     40 #define ID_TEAMARENA		15
     41 #define ID_MODS					16
     42 #define ID_EXIT					17
     43 
     44 #define MAIN_BANNER_MODEL				"models/mapobjects/banner/banner5.md3"
     45 #define MAIN_MENU_VERTICAL_SPACING		34
     46 
     47 
     48 typedef struct {
     49 	menuframework_s	menu;
     50 
     51 	menutext_s		singleplayer;
     52 	menutext_s		multiplayer;
     53 	menutext_s		setup;
     54 	menutext_s		demos;
     55 	menutext_s		cinematics;
     56 	menutext_s		teamArena;
     57 	menutext_s		mods;
     58 	menutext_s		exit;
     59 
     60 	qhandle_t		bannerModel;
     61 } mainmenu_t;
     62 
     63 
     64 static mainmenu_t s_main;
     65 
     66 typedef struct {
     67 	menuframework_s menu;	
     68 	char errorMessage[4096];
     69 } errorMessage_t;
     70 
     71 static errorMessage_t s_errorMessage;
     72 
     73 /*
     74 =================
     75 MainMenu_ExitAction
     76 =================
     77 */
     78 static void MainMenu_ExitAction( qboolean result ) {
     79 	if( !result ) {
     80 		return;
     81 	}
     82 	UI_PopMenu();
     83 	UI_CreditMenu();
     84 }
     85 
     86 
     87 
     88 /*
     89 =================
     90 Main_MenuEvent
     91 =================
     92 */
     93 void Main_MenuEvent (void* ptr, int event) {
     94 	if( event != QM_ACTIVATED ) {
     95 		return;
     96 	}
     97 
     98 	switch( ((menucommon_s*)ptr)->id ) {
     99 	case ID_SINGLEPLAYER:
    100 		UI_SPLevelMenu();
    101 		break;
    102 
    103 	case ID_MULTIPLAYER:
    104 		UI_ArenaServersMenu();
    105 		break;
    106 
    107 	case ID_SETUP:
    108 		UI_SetupMenu();
    109 		break;
    110 
    111 	case ID_DEMOS:
    112 		UI_DemosMenu();
    113 		break;
    114 
    115 	case ID_CINEMATICS:
    116 		UI_CinematicsMenu();
    117 		break;
    118 
    119 	case ID_MODS:
    120 		UI_ModsMenu();
    121 		break;
    122 
    123 	case ID_TEAMARENA:
    124 		trap_Cvar_Set( "fs_game", "missionpack");
    125 		trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
    126 		break;
    127 
    128 	case ID_EXIT:
    129 		UI_ConfirmMenu( "EXIT GAME?", NULL, MainMenu_ExitAction );
    130 		break;
    131 	}
    132 }
    133 
    134 
    135 /*
    136 ===============
    137 MainMenu_Cache
    138 ===============
    139 */
    140 void MainMenu_Cache( void ) {
    141 	s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );
    142 }
    143 
    144 sfxHandle_t ErrorMessage_Key(int key)
    145 {
    146 	trap_Cvar_Set( "com_errorMessage", "" );
    147 	UI_MainMenu();
    148 	return (menu_null_sound);
    149 }
    150 
    151 /*
    152 ===============
    153 Main_MenuDraw
    154 TTimo: this function is common to the main menu and errorMessage menu
    155 ===============
    156 */
    157 
    158 static void Main_MenuDraw( void ) {
    159 	refdef_t		refdef;
    160 	refEntity_t		ent;
    161 	vec3_t			origin;
    162 	vec3_t			angles;
    163 	float			adjust;
    164 	float			x, y, w, h;
    165 	vec4_t			color = {0.5, 0, 0, 1};
    166 
    167 	// setup the refdef
    168 
    169 	memset( &refdef, 0, sizeof( refdef ) );
    170 
    171 	refdef.rdflags = RDF_NOWORLDMODEL;
    172 
    173 	AxisClear( refdef.viewaxis );
    174 
    175 	x = 0;
    176 	y = 0;
    177 	w = 640;
    178 	h = 120;
    179 	UI_AdjustFrom640( &x, &y, &w, &h );
    180 	refdef.x = x;
    181 	refdef.y = y;
    182 	refdef.width = w;
    183 	refdef.height = h;
    184 
    185 	adjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );
    186 	refdef.fov_x = 60 + adjust;
    187 	refdef.fov_y = 19.6875 + adjust;
    188 
    189 	refdef.time = uis.realtime;
    190 
    191 	origin[0] = 300;
    192 	origin[1] = 0;
    193 	origin[2] = -32;
    194 
    195 	trap_R_ClearScene();
    196 
    197 	// add the model
    198 
    199 	memset( &ent, 0, sizeof(ent) );
    200 
    201 	adjust = 5.0 * sin( (float)uis.realtime / 5000 );
    202 	VectorSet( angles, 0, 180 + adjust, 0 );
    203 	AnglesToAxis( angles, ent.axis );
    204 	ent.hModel = s_main.bannerModel;
    205 	VectorCopy( origin, ent.origin );
    206 	VectorCopy( origin, ent.lightingOrigin );
    207 	ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
    208 	VectorCopy( ent.origin, ent.oldorigin );
    209 
    210 	trap_R_AddRefEntityToScene( &ent );
    211 
    212 	trap_R_RenderScene( &refdef );
    213 	
    214 	if (strlen(s_errorMessage.errorMessage))
    215 	{
    216 		UI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
    217 	}
    218 	else
    219 	{
    220 		// standard menu drawing
    221 		Menu_Draw( &s_main.menu );		
    222 	}
    223 
    224 	if (uis.demoversion) {
    225 		UI_DrawProportionalString( 320, 372, "DEMO      FOR MATURE AUDIENCES      DEMO", UI_CENTER|UI_SMALLFONT, color );
    226 		UI_DrawString( 320, 400, "Quake III Arena(c) 1999-2000, Id Software, Inc.  All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
    227 	} else {
    228 		UI_DrawString( 320, 450, "Quake III Arena(c) 1999-2000, Id Software, Inc.  All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
    229 	}
    230 }
    231 
    232 
    233 /*
    234 ===============
    235 UI_TeamArenaExists
    236 ===============
    237 */
    238 static qboolean UI_TeamArenaExists( void ) {
    239 	int		numdirs;
    240 	char	dirlist[2048];
    241 	char	*dirptr;
    242   char  *descptr;
    243 	int		i;
    244 	int		dirlen;
    245 
    246 	numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
    247 	dirptr  = dirlist;
    248 	for( i = 0; i < numdirs; i++ ) {
    249 		dirlen = strlen( dirptr ) + 1;
    250     descptr = dirptr + dirlen;
    251 		if (Q_stricmp(dirptr, "missionpack") == 0) {
    252 			return qtrue;
    253 		}
    254     dirptr += dirlen + strlen(descptr) + 1;
    255 	}
    256 	return qfalse;
    257 }
    258 
    259 
    260 /*
    261 ===============
    262 UI_MainMenu
    263 
    264 The main menu only comes up when not in a game,
    265 so make sure that the attract loop server is down
    266 and that local cinematics are killed
    267 ===============
    268 */
    269 void UI_MainMenu( void ) {
    270 	int		y;
    271 	qboolean teamArena = qfalse;
    272 	int		style = UI_CENTER | UI_DROPSHADOW;
    273 
    274 	trap_Cvar_Set( "sv_killserver", "1" );
    275 
    276 	if( !uis.demoversion && !ui_cdkeychecked.integer ) {
    277 		char	key[17];
    278 
    279 		trap_GetCDKey( key, sizeof(key) );
    280 		if( trap_VerifyCDKey( key, NULL ) == qfalse ) {
    281 			UI_CDKeyMenu();
    282 			return;
    283 		}
    284 	}
    285 	
    286 	memset( &s_main, 0 ,sizeof(mainmenu_t) );
    287 	memset( &s_errorMessage, 0 ,sizeof(errorMessage_t) );
    288 
    289 	// com_errorMessage would need that too
    290 	MainMenu_Cache();
    291 	
    292 	trap_Cvar_VariableStringBuffer( "com_errorMessage", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) );
    293 	if (strlen(s_errorMessage.errorMessage))
    294 	{	
    295 		s_errorMessage.menu.draw = Main_MenuDraw;
    296 		s_errorMessage.menu.key = ErrorMessage_Key;
    297 		s_errorMessage.menu.fullscreen = qtrue;
    298 		s_errorMessage.menu.wrapAround = qtrue;
    299 		s_errorMessage.menu.showlogo = qtrue;		
    300 
    301 		trap_Key_SetCatcher( KEYCATCH_UI );
    302 		uis.menusp = 0;
    303 		UI_PushMenu ( &s_errorMessage.menu );
    304 		
    305 		return;
    306 	}
    307 
    308 	s_main.menu.draw = Main_MenuDraw;
    309 	s_main.menu.fullscreen = qtrue;
    310 	s_main.menu.wrapAround = qtrue;
    311 	s_main.menu.showlogo = qtrue;
    312 
    313 	y = 134;
    314 	s_main.singleplayer.generic.type		= MTYPE_PTEXT;
    315 	s_main.singleplayer.generic.flags		= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    316 	s_main.singleplayer.generic.x			= 320;
    317 	s_main.singleplayer.generic.y			= y;
    318 	s_main.singleplayer.generic.id			= ID_SINGLEPLAYER;
    319 	s_main.singleplayer.generic.callback	= Main_MenuEvent; 
    320 	s_main.singleplayer.string				= "SINGLE PLAYER";
    321 	s_main.singleplayer.color				= color_red;
    322 	s_main.singleplayer.style				= style;
    323 
    324 	y += MAIN_MENU_VERTICAL_SPACING;
    325 	s_main.multiplayer.generic.type			= MTYPE_PTEXT;
    326 	s_main.multiplayer.generic.flags		= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    327 	s_main.multiplayer.generic.x			= 320;
    328 	s_main.multiplayer.generic.y			= y;
    329 	s_main.multiplayer.generic.id			= ID_MULTIPLAYER;
    330 	s_main.multiplayer.generic.callback		= Main_MenuEvent; 
    331 	s_main.multiplayer.string				= "MULTIPLAYER";
    332 	s_main.multiplayer.color				= color_red;
    333 	s_main.multiplayer.style				= style;
    334 
    335 	y += MAIN_MENU_VERTICAL_SPACING;
    336 	s_main.setup.generic.type				= MTYPE_PTEXT;
    337 	s_main.setup.generic.flags				= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    338 	s_main.setup.generic.x					= 320;
    339 	s_main.setup.generic.y					= y;
    340 	s_main.setup.generic.id					= ID_SETUP;
    341 	s_main.setup.generic.callback			= Main_MenuEvent; 
    342 	s_main.setup.string						= "SETUP";
    343 	s_main.setup.color						= color_red;
    344 	s_main.setup.style						= style;
    345 
    346 	y += MAIN_MENU_VERTICAL_SPACING;
    347 	s_main.demos.generic.type				= MTYPE_PTEXT;
    348 	s_main.demos.generic.flags				= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    349 	s_main.demos.generic.x					= 320;
    350 	s_main.demos.generic.y					= y;
    351 	s_main.demos.generic.id					= ID_DEMOS;
    352 	s_main.demos.generic.callback			= Main_MenuEvent; 
    353 	s_main.demos.string						= "DEMOS";
    354 	s_main.demos.color						= color_red;
    355 	s_main.demos.style						= style;
    356 
    357 	y += MAIN_MENU_VERTICAL_SPACING;
    358 	s_main.cinematics.generic.type			= MTYPE_PTEXT;
    359 	s_main.cinematics.generic.flags			= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    360 	s_main.cinematics.generic.x				= 320;
    361 	s_main.cinematics.generic.y				= y;
    362 	s_main.cinematics.generic.id			= ID_CINEMATICS;
    363 	s_main.cinematics.generic.callback		= Main_MenuEvent; 
    364 	s_main.cinematics.string				= "CINEMATICS";
    365 	s_main.cinematics.color					= color_red;
    366 	s_main.cinematics.style					= style;
    367 
    368 	if (UI_TeamArenaExists()) {
    369 		teamArena = qtrue;
    370 		y += MAIN_MENU_VERTICAL_SPACING;
    371 		s_main.teamArena.generic.type			= MTYPE_PTEXT;
    372 		s_main.teamArena.generic.flags			= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    373 		s_main.teamArena.generic.x				= 320;
    374 		s_main.teamArena.generic.y				= y;
    375 		s_main.teamArena.generic.id				= ID_TEAMARENA;
    376 		s_main.teamArena.generic.callback		= Main_MenuEvent; 
    377 		s_main.teamArena.string					= "TEAM ARENA";
    378 		s_main.teamArena.color					= color_red;
    379 		s_main.teamArena.style					= style;
    380 	}
    381 
    382 	y += MAIN_MENU_VERTICAL_SPACING;
    383 	s_main.mods.generic.type			= MTYPE_PTEXT;
    384 	s_main.mods.generic.flags			= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    385 	s_main.mods.generic.x				= 320;
    386 	s_main.mods.generic.y				= y;
    387 	s_main.mods.generic.id				= ID_MODS;
    388 	s_main.mods.generic.callback		= Main_MenuEvent; 
    389 	s_main.mods.string					= "MODS";
    390 	s_main.mods.color					= color_red;
    391 	s_main.mods.style					= style;
    392 
    393 	y += MAIN_MENU_VERTICAL_SPACING;
    394 	s_main.exit.generic.type				= MTYPE_PTEXT;
    395 	s_main.exit.generic.flags				= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
    396 	s_main.exit.generic.x					= 320;
    397 	s_main.exit.generic.y					= y;
    398 	s_main.exit.generic.id					= ID_EXIT;
    399 	s_main.exit.generic.callback			= Main_MenuEvent; 
    400 	s_main.exit.string						= "EXIT";
    401 	s_main.exit.color						= color_red;
    402 	s_main.exit.style						= style;
    403 
    404 	Menu_AddItem( &s_main.menu,	&s_main.singleplayer );
    405 	Menu_AddItem( &s_main.menu,	&s_main.multiplayer );
    406 	Menu_AddItem( &s_main.menu,	&s_main.setup );
    407 	Menu_AddItem( &s_main.menu,	&s_main.demos );
    408 	Menu_AddItem( &s_main.menu,	&s_main.cinematics );
    409 	if (teamArena) {
    410 		Menu_AddItem( &s_main.menu,	&s_main.teamArena );
    411 	}
    412 	Menu_AddItem( &s_main.menu,	&s_main.mods );
    413 	Menu_AddItem( &s_main.menu,	&s_main.exit );             
    414 
    415 	trap_Key_SetCatcher( KEYCATCH_UI );
    416 	uis.menusp = 0;
    417 	UI_PushMenu ( &s_main.menu );
    418 		
    419 }