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 Quake III Arena source code; 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 */
MainMenu_ExitAction(qboolean result)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 */
Main_MenuEvent(void * ptr,int event)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?", 0, MainMenu_ExitAction );
130 		break;
131 	}
132 }
133 
134 
135 /*
136 ===============
137 MainMenu_Cache
138 ===============
139 */
MainMenu_Cache(void)140 void MainMenu_Cache( void ) {
141 	s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );
142 }
143 
ErrorMessage_Key(int key)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 
Main_MenuDraw(void)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 */
UI_TeamArenaExists(void)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 */
UI_MainMenu(void)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 }
420