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 	UI_ATOMS.C
25 
26 	User interface building blocks and support functions.
27 **********************************************************************/
28 #include "ui_local.h"
29 
30 qboolean		m_entersound;		// after a frame, so caching won't disrupt the sound
31 
Com_Error(int level,const char * error,...)32 void QDECL Com_Error( int level, const char *error, ... ) {
33 	va_list		argptr;
34 	char		text[1024];
35 
36 	va_start (argptr, error);
37 	Q_vsnprintf (text, sizeof(text), error, argptr);
38 	va_end (argptr);
39 
40 	trap_Error( va("%s", text) );
41 }
42 
Com_Printf(const char * msg,...)43 void QDECL Com_Printf( const char *msg, ... ) {
44 	va_list		argptr;
45 	char		text[1024];
46 
47 	va_start (argptr, msg);
48 	Q_vsnprintf (text, sizeof(text), msg, argptr);
49 	va_end (argptr);
50 
51 	trap_Print( va("%s", text) );
52 }
53 
54 qboolean newUI = qfalse;
55 
56 
57 /*
58 =================
59 UI_ClampCvar
60 =================
61 */
UI_ClampCvar(float min,float max,float value)62 float UI_ClampCvar( float min, float max, float value )
63 {
64 	if ( value < min ) return min;
65 	if ( value > max ) return max;
66 	return value;
67 }
68 
69 /*
70 =================
71 UI_StartDemoLoop
72 =================
73 */
UI_StartDemoLoop(void)74 void UI_StartDemoLoop( void ) {
75 	trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
76 }
77 
78 
79 #ifndef MISSIONPACK
NeedCDAction(qboolean result)80 static void NeedCDAction( qboolean result ) {
81 	if ( !result ) {
82 		trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
83 	}
84 }
85 #endif // MISSIONPACK
86 
87 #ifndef MISSIONPACK
NeedCDKeyAction(qboolean result)88 static void NeedCDKeyAction( qboolean result ) {
89 	if ( !result ) {
90 		trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
91 	}
92 }
93 #endif // MISSIONPACK
94 
UI_Argv(int arg)95 char *UI_Argv( int arg ) {
96 	static char	buffer[MAX_STRING_CHARS];
97 
98 	trap_Argv( arg, buffer, sizeof( buffer ) );
99 
100 	return buffer;
101 }
102 
103 
UI_Cvar_VariableString(const char * var_name)104 char *UI_Cvar_VariableString( const char *var_name ) {
105 	static char	buffer[MAX_STRING_CHARS];
106 
107 	trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
108 
109 	return buffer;
110 }
111 
112 
113 
UI_SetBestScores(postGameInfo_t * newInfo,qboolean postGame)114 void UI_SetBestScores(postGameInfo_t *newInfo, qboolean postGame) {
115 	trap_Cvar_Set("ui_scoreAccuracy",     va("%i%%", newInfo->accuracy));
116 	trap_Cvar_Set("ui_scoreImpressives",	va("%i", newInfo->impressives));
117 	trap_Cvar_Set("ui_scoreExcellents", 	va("%i", newInfo->excellents));
118 	trap_Cvar_Set("ui_scoreDefends", 			va("%i", newInfo->defends));
119 	trap_Cvar_Set("ui_scoreAssists", 			va("%i", newInfo->assists));
120 	trap_Cvar_Set("ui_scoreGauntlets", 		va("%i", newInfo->gauntlets));
121 	trap_Cvar_Set("ui_scoreScore", 				va("%i", newInfo->score));
122 	trap_Cvar_Set("ui_scorePerfect",	 		va("%i", newInfo->perfects));
123 	trap_Cvar_Set("ui_scoreTeam",					va("%i to %i", newInfo->redScore, newInfo->blueScore));
124 	trap_Cvar_Set("ui_scoreBase",					va("%i", newInfo->baseScore));
125 	trap_Cvar_Set("ui_scoreTimeBonus",		va("%i", newInfo->timeBonus));
126 	trap_Cvar_Set("ui_scoreSkillBonus",		va("%i", newInfo->skillBonus));
127 	trap_Cvar_Set("ui_scoreShutoutBonus",	va("%i", newInfo->shutoutBonus));
128 	trap_Cvar_Set("ui_scoreTime",					va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
129 	trap_Cvar_Set("ui_scoreCaptures",		va("%i", newInfo->captures));
130   if (postGame) {
131 		trap_Cvar_Set("ui_scoreAccuracy2",     va("%i%%", newInfo->accuracy));
132 		trap_Cvar_Set("ui_scoreImpressives2",	va("%i", newInfo->impressives));
133 		trap_Cvar_Set("ui_scoreExcellents2", 	va("%i", newInfo->excellents));
134 		trap_Cvar_Set("ui_scoreDefends2", 			va("%i", newInfo->defends));
135 		trap_Cvar_Set("ui_scoreAssists2", 			va("%i", newInfo->assists));
136 		trap_Cvar_Set("ui_scoreGauntlets2", 		va("%i", newInfo->gauntlets));
137 		trap_Cvar_Set("ui_scoreScore2", 				va("%i", newInfo->score));
138 		trap_Cvar_Set("ui_scorePerfect2",	 		va("%i", newInfo->perfects));
139 		trap_Cvar_Set("ui_scoreTeam2",					va("%i to %i", newInfo->redScore, newInfo->blueScore));
140 		trap_Cvar_Set("ui_scoreBase2",					va("%i", newInfo->baseScore));
141 		trap_Cvar_Set("ui_scoreTimeBonus2",		va("%i", newInfo->timeBonus));
142 		trap_Cvar_Set("ui_scoreSkillBonus2",		va("%i", newInfo->skillBonus));
143 		trap_Cvar_Set("ui_scoreShutoutBonus2",	va("%i", newInfo->shutoutBonus));
144 		trap_Cvar_Set("ui_scoreTime2",					va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
145 		trap_Cvar_Set("ui_scoreCaptures2",		va("%i", newInfo->captures));
146 	}
147 }
148 
UI_LoadBestScores(const char * map,int game)149 void UI_LoadBestScores(const char *map, int game) {
150 	char		fileName[MAX_QPATH];
151 	fileHandle_t f;
152 	postGameInfo_t newInfo;
153 	memset(&newInfo, 0, sizeof(postGameInfo_t));
154 	Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
155 	if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
156 		int size = 0;
157 		trap_FS_Read(&size, sizeof(int), f);
158 		if (size == sizeof(postGameInfo_t)) {
159 			trap_FS_Read(&newInfo, sizeof(postGameInfo_t), f);
160 		}
161 		trap_FS_FCloseFile(f);
162 	}
163 	UI_SetBestScores(&newInfo, qfalse);
164 
165 	Com_sprintf(fileName, MAX_QPATH, "demos/%s_%d.dm_%d", map, game, (int)trap_Cvar_VariableValue("protocol"));
166 	uiInfo.demoAvailable = qfalse;
167 	if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
168 		uiInfo.demoAvailable = qtrue;
169 		trap_FS_FCloseFile(f);
170 	}
171 }
172 
173 /*
174 ===============
175 UI_ClearScores
176 ===============
177 */
UI_ClearScores(void)178 void UI_ClearScores(void) {
179 	char	gameList[4096];
180 	char *gameFile;
181 	int		i, len, count, size;
182 	fileHandle_t f;
183 	postGameInfo_t newInfo;
184 
185 	count = trap_FS_GetFileList( "games", "game", gameList, sizeof(gameList) );
186 
187 	size = sizeof(postGameInfo_t);
188 	memset(&newInfo, 0, size);
189 
190 	if (count > 0) {
191 		gameFile = gameList;
192 		for ( i = 0; i < count; i++ ) {
193 			len = strlen(gameFile);
194 			if (trap_FS_FOpenFile(va("games/%s",gameFile), &f, FS_WRITE) >= 0) {
195 				trap_FS_Write(&size, sizeof(int), f);
196 				trap_FS_Write(&newInfo, size, f);
197 				trap_FS_FCloseFile(f);
198 			}
199 			gameFile += len + 1;
200 		}
201 	}
202 
203 	UI_SetBestScores(&newInfo, qfalse);
204 
205 }
206 
207 
208 
UI_Cache_f(void)209 static void	UI_Cache_f( void ) {
210 	Display_CacheAll();
211 }
212 
213 /*
214 =======================
215 UI_CalcPostGameStats
216 =======================
217 */
UI_CalcPostGameStats(void)218 static void UI_CalcPostGameStats( void ) {
219 	char		map[MAX_QPATH];
220 	char		fileName[MAX_QPATH];
221 	char		info[MAX_INFO_STRING];
222 	fileHandle_t f;
223 	int size, game, time, adjustedTime;
224 	postGameInfo_t oldInfo;
225 	postGameInfo_t newInfo;
226 	qboolean newHigh = qfalse;
227 
228 	trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
229 	Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
230 	game = atoi(Info_ValueForKey(info, "g_gametype"));
231 
232 	// compose file name
233 	Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
234 	// see if we have one already
235 	memset(&oldInfo, 0, sizeof(postGameInfo_t));
236 	if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
237 	// if so load it
238 		size = 0;
239 		trap_FS_Read(&size, sizeof(int), f);
240 		if (size == sizeof(postGameInfo_t)) {
241 			trap_FS_Read(&oldInfo, sizeof(postGameInfo_t), f);
242 		}
243 		trap_FS_FCloseFile(f);
244 	}
245 
246 	newInfo.accuracy = atoi(UI_Argv(3));
247 	newInfo.impressives = atoi(UI_Argv(4));
248 	newInfo.excellents = atoi(UI_Argv(5));
249 	newInfo.defends = atoi(UI_Argv(6));
250 	newInfo.assists = atoi(UI_Argv(7));
251 	newInfo.gauntlets = atoi(UI_Argv(8));
252 	newInfo.baseScore = atoi(UI_Argv(9));
253 	newInfo.perfects = atoi(UI_Argv(10));
254 	newInfo.redScore = atoi(UI_Argv(11));
255 	newInfo.blueScore = atoi(UI_Argv(12));
256 	time = atoi(UI_Argv(13));
257 	newInfo.captures = atoi(UI_Argv(14));
258 
259 	newInfo.time = (time - trap_Cvar_VariableValue("ui_matchStartTime")) / 1000;
260 	adjustedTime = uiInfo.mapList[ui_currentMap.integer].timeToBeat[game];
261 	if (newInfo.time < adjustedTime) {
262 		newInfo.timeBonus = (adjustedTime - newInfo.time) * 10;
263 	} else {
264 		newInfo.timeBonus = 0;
265 	}
266 
267 	if (newInfo.redScore > newInfo.blueScore && newInfo.blueScore <= 0) {
268 		newInfo.shutoutBonus = 100;
269 	} else {
270 		newInfo.shutoutBonus = 0;
271 	}
272 
273 	newInfo.skillBonus = trap_Cvar_VariableValue("g_spSkill");
274 	if (newInfo.skillBonus <= 0) {
275 		newInfo.skillBonus = 1;
276 	}
277 	newInfo.score = newInfo.baseScore + newInfo.shutoutBonus + newInfo.timeBonus;
278 	newInfo.score *= newInfo.skillBonus;
279 
280 	// see if the score is higher for this one
281 	newHigh = (newInfo.redScore > newInfo.blueScore && newInfo.score > oldInfo.score);
282 
283 	if  (newHigh) {
284 		// if so write out the new one
285 		uiInfo.newHighScoreTime = uiInfo.uiDC.realTime + 20000;
286 		if (trap_FS_FOpenFile(fileName, &f, FS_WRITE) >= 0) {
287 			size = sizeof(postGameInfo_t);
288 			trap_FS_Write(&size, sizeof(int), f);
289 			trap_FS_Write(&newInfo, sizeof(postGameInfo_t), f);
290 			trap_FS_FCloseFile(f);
291 		}
292 	}
293 
294 	if (newInfo.time < oldInfo.time) {
295 		uiInfo.newBestTime = uiInfo.uiDC.realTime + 20000;
296 	}
297 
298 	// put back all the ui overrides
299 	trap_Cvar_Set("capturelimit", UI_Cvar_VariableString("ui_saveCaptureLimit"));
300 	trap_Cvar_Set("fraglimit", UI_Cvar_VariableString("ui_saveFragLimit"));
301 	trap_Cvar_Set("cg_drawTimer", UI_Cvar_VariableString("ui_drawTimer"));
302 	trap_Cvar_Set("g_doWarmup", UI_Cvar_VariableString("ui_doWarmup"));
303 	trap_Cvar_Set("g_Warmup", UI_Cvar_VariableString("ui_Warmup"));
304 	trap_Cvar_Set("sv_pure", UI_Cvar_VariableString("ui_pure"));
305 	trap_Cvar_Set("g_friendlyFire", UI_Cvar_VariableString("ui_friendlyFire"));
306 
307 	UI_SetBestScores(&newInfo, qtrue);
308 	UI_ShowPostGame(newHigh);
309 
310 
311 }
312 
313 
314 /*
315 =================
316 UI_ConsoleCommand
317 =================
318 */
UI_ConsoleCommand(int realTime)319 qboolean UI_ConsoleCommand( int realTime ) {
320 	char	*cmd;
321 
322 	uiInfo.uiDC.frameTime = realTime - uiInfo.uiDC.realTime;
323 	uiInfo.uiDC.realTime = realTime;
324 
325 	cmd = UI_Argv( 0 );
326 
327 	// ensure minimum menu data is available
328 	//Menu_Cache();
329 
330 	if ( Q_stricmp (cmd, "ui_test") == 0 ) {
331 		UI_ShowPostGame(qtrue);
332 	}
333 
334 	if ( Q_stricmp (cmd, "ui_report") == 0 ) {
335 		UI_Report();
336 		return qtrue;
337 	}
338 
339 	if ( Q_stricmp (cmd, "ui_load") == 0 ) {
340 		UI_Load();
341 		return qtrue;
342 	}
343 
344 	if ( Q_stricmp (cmd, "remapShader") == 0 ) {
345 		if (trap_Argc() == 4) {
346 			char shader1[MAX_QPATH];
347 			char shader2[MAX_QPATH];
348 			char shader3[MAX_QPATH];
349 
350 			Q_strncpyz(shader1, UI_Argv(1), sizeof(shader1));
351 			Q_strncpyz(shader2, UI_Argv(2), sizeof(shader2));
352 			Q_strncpyz(shader3, UI_Argv(3), sizeof(shader3));
353 
354 			trap_R_RemapShader(shader1, shader2, shader3);
355 			return qtrue;
356 		}
357 	}
358 
359 	if ( Q_stricmp (cmd, "postgame") == 0 ) {
360 		UI_CalcPostGameStats();
361 		return qtrue;
362 	}
363 
364 	if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
365 		UI_Cache_f();
366 		return qtrue;
367 	}
368 
369 	if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
370 		//UI_TeamOrdersMenu_f();
371 		return qtrue;
372 	}
373 
374 
375 	if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
376 		//UI_CDKeyMenu_f();
377 		return qtrue;
378 	}
379 
380 	return qfalse;
381 }
382 
383 /*
384 =================
385 UI_Shutdown
386 =================
387 */
UI_Shutdown(void)388 void UI_Shutdown( void ) {
389 }
390 
391 /*
392 ================
393 UI_AdjustFrom640
394 
395 Adjusted for resolution and screen aspect ratio
396 ================
397 */
UI_AdjustFrom640(float * x,float * y,float * w,float * h)398 void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
399 	// expect valid pointers
400 #if 0
401 	*x = *x * uiInfo.uiDC.scale + uiInfo.uiDC.bias;
402 	*y *= uiInfo.uiDC.scale;
403 	*w *= uiInfo.uiDC.scale;
404 	*h *= uiInfo.uiDC.scale;
405 #endif
406 
407 	*x *= uiInfo.uiDC.xscale;
408 	*y *= uiInfo.uiDC.yscale;
409 	*w *= uiInfo.uiDC.xscale;
410 	*h *= uiInfo.uiDC.yscale;
411 
412 }
413 
UI_DrawNamedPic(float x,float y,float width,float height,const char * picname)414 void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
415 	qhandle_t	hShader;
416 
417 	hShader = trap_R_RegisterShaderNoMip( picname );
418 	UI_AdjustFrom640( &x, &y, &width, &height );
419 	trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
420 }
421 
UI_DrawHandlePic(float x,float y,float w,float h,qhandle_t hShader)422 void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
423 	float	s0;
424 	float	s1;
425 	float	t0;
426 	float	t1;
427 
428 	if( w < 0 ) {	// flip about vertical
429 		w  = -w;
430 		s0 = 1;
431 		s1 = 0;
432 	}
433 	else {
434 		s0 = 0;
435 		s1 = 1;
436 	}
437 
438 	if( h < 0 ) {	// flip about horizontal
439 		h  = -h;
440 		t0 = 1;
441 		t1 = 0;
442 	}
443 	else {
444 		t0 = 0;
445 		t1 = 1;
446 	}
447 
448 	UI_AdjustFrom640( &x, &y, &w, &h );
449 	trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
450 }
451 
452 /*
453 ================
454 UI_FillRect
455 
456 Coordinates are 640*480 virtual values
457 =================
458 */
UI_FillRect(float x,float y,float width,float height,const float * color)459 void UI_FillRect( float x, float y, float width, float height, const float *color ) {
460 	trap_R_SetColor( color );
461 
462 	UI_AdjustFrom640( &x, &y, &width, &height );
463 	trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
464 
465 	trap_R_SetColor( NULL );
466 }
467 
UI_DrawSides(float x,float y,float w,float h)468 void UI_DrawSides(float x, float y, float w, float h) {
469 	UI_AdjustFrom640( &x, &y, &w, &h );
470 	trap_R_DrawStretchPic( x, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
471 	trap_R_DrawStretchPic( x + w - 1, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
472 }
473 
UI_DrawTopBottom(float x,float y,float w,float h)474 void UI_DrawTopBottom(float x, float y, float w, float h) {
475 	UI_AdjustFrom640( &x, &y, &w, &h );
476 	trap_R_DrawStretchPic( x, y, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
477 	trap_R_DrawStretchPic( x, y + h - 1, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
478 }
479 /*
480 ================
481 UI_DrawRect
482 
483 Coordinates are 640*480 virtual values
484 =================
485 */
UI_DrawRect(float x,float y,float width,float height,const float * color)486 void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
487 	trap_R_SetColor( color );
488 
489   UI_DrawTopBottom(x, y, width, height);
490   UI_DrawSides(x, y, width, height);
491 
492 	trap_R_SetColor( NULL );
493 }
494 
UI_SetColor(const float * rgba)495 void UI_SetColor( const float *rgba ) {
496 	trap_R_SetColor( rgba );
497 }
498 
UI_UpdateScreen(void)499 void UI_UpdateScreen( void ) {
500 	trap_UpdateScreen();
501 }
502 
503 
UI_DrawTextBox(int x,int y,int width,int lines)504 void UI_DrawTextBox (int x, int y, int width, int lines)
505 {
506 	UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
507 	UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
508 }
509 
UI_CursorInRect(int x,int y,int width,int height)510 qboolean UI_CursorInRect (int x, int y, int width, int height)
511 {
512 	if (uiInfo.uiDC.cursorx < x ||
513 		uiInfo.uiDC.cursory < y ||
514 		uiInfo.uiDC.cursorx > x+width ||
515 		uiInfo.uiDC.cursory > y+height)
516 		return qfalse;
517 
518 	return qtrue;
519 }
520