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