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 }