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 USER INTERFACE MAIN
27
28 =======================================================================
29 */
30
31 // use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
32 //#define PRE_RELEASE_TADEMO
33
34 #include "ui_local.h"
35
36 uiInfo_t uiInfo;
37
38 static const char *MonthAbbrev[] = {
39 "Jan","Feb","Mar",
40 "Apr","May","Jun",
41 "Jul","Aug","Sep",
42 "Oct","Nov","Dec"
43 };
44
45
46 static const char *skillLevels[] = {
47 "I Can Win",
48 "Bring It On",
49 "Hurt Me Plenty",
50 "Hardcore",
51 "Nightmare"
52 };
53
54 static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
55
56
57 static const char *netSources[] = {
58 "Local",
59 "Mplayer",
60 "Internet",
61 "Favorites"
62 };
63 static const int numNetSources = sizeof(netSources) / sizeof(const char*);
64
65 static const serverFilter_t serverFilters[] = {
66 {"All", "" },
67 {"Quake 3 Arena", "" },
68 {"Team Arena", "missionpack" },
69 {"Rocket Arena", "arena" },
70 {"Alliance", "alliance20" },
71 {"Weapons Factory Arena", "wfa" },
72 {"OSP", "osp" },
73 };
74
75 static const char *teamArenaGameTypes[] = {
76 "FFA",
77 "TOURNAMENT",
78 "SP",
79 "TEAM DM",
80 "CTF",
81 "1FCTF",
82 "OVERLOAD",
83 "HARVESTER",
84 "TEAMTOURNAMENT"
85 };
86
87 static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
88
89
90 static const char *teamArenaGameNames[] = {
91 "Free For All",
92 "Tournament",
93 "Single Player",
94 "Team Deathmatch",
95 "Capture the Flag",
96 "One Flag CTF",
97 "Overload",
98 "Harvester",
99 "Team Tournament",
100 };
101
102 static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
103
104
105 static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
106
107 static const char *sortKeys[] = {
108 "Server Name",
109 "Map Name",
110 "Open Player Spots",
111 "Game Type",
112 "Ping Time"
113 };
114 static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
115
116 static char* netnames[] = {
117 "???",
118 "UDP",
119 NULL
120 };
121
122 #ifndef MISSIONPACK
123 static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
124 #endif
125
126 static int gamecodetoui[] = {4,2,3,0,5,1,6};
127 static int uitogamecode[] = {4,6,2,3,1,5,7};
128
129
130 static void UI_StartServerRefresh(qboolean full);
131 static void UI_StopServerRefresh( void );
132 static void UI_DoServerRefresh( void );
133 static void UI_FeederSelection(float feederID, int index);
134 static void UI_BuildServerDisplayList(qboolean force);
135 static void UI_BuildServerStatus(qboolean force);
136 static void UI_BuildFindPlayerList(qboolean force);
137 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
138 static int UI_MapCountByGameType(qboolean singlePlayer);
139 static int UI_HeadCountByTeam( void );
140 static void UI_ParseGameInfo(const char *teamFile);
141 static void UI_ParseTeamInfo(const char *teamFile);
142 static const char *UI_SelectedMap(int index, int *actual);
143 static const char *UI_SelectedHead(int index, int *actual);
144 static int UI_GetIndexFromSelection(int actual);
145
146 int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
147
148 /*
149 ================
150 vmMain
151
152 This is the only way control passes into the module.
153 This must be the very first function compiled into the .qvm file
154 ================
155 */
156 vmCvar_t ui_new;
157 vmCvar_t ui_debug;
158 vmCvar_t ui_initialized;
159 vmCvar_t ui_teamArenaFirstRun;
160
161 void _UI_Init( qboolean );
162 void _UI_Shutdown( void );
163 void _UI_KeyEvent( int key, qboolean down );
164 void _UI_MouseEvent( int dx, int dy );
165 void _UI_Refresh( int realtime );
166 qboolean _UI_IsFullscreen( void );
vmMain(int command,int arg0,int arg1,int arg2,int arg3,int arg4,int arg5,int arg6,int arg7,int arg8,int arg9,int arg10,int arg11)167 intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
168 switch ( command ) {
169 case UI_GETAPIVERSION:
170 return UI_API_VERSION;
171
172 case UI_INIT:
173 _UI_Init(arg0);
174 return 0;
175
176 case UI_SHUTDOWN:
177 _UI_Shutdown();
178 return 0;
179
180 case UI_KEY_EVENT:
181 _UI_KeyEvent( arg0, arg1 );
182 return 0;
183
184 case UI_MOUSE_EVENT:
185 _UI_MouseEvent( arg0, arg1 );
186 return 0;
187
188 case UI_REFRESH:
189 _UI_Refresh( arg0 );
190 return 0;
191
192 case UI_IS_FULLSCREEN:
193 return _UI_IsFullscreen();
194
195 case UI_SET_ACTIVE_MENU:
196 _UI_SetActiveMenu( arg0 );
197 return 0;
198
199 case UI_CONSOLE_COMMAND:
200 return UI_ConsoleCommand(arg0);
201
202 case UI_DRAW_CONNECT_SCREEN:
203 UI_DrawConnectScreen( arg0 );
204 return 0;
205 case UI_HASUNIQUECDKEY: // mod authors need to observe this
206 return qtrue; // change this to qfalse for mods!
207
208 }
209
210 return -1;
211 }
212
213
214
AssetCache(void)215 void AssetCache( void ) {
216 int n;
217 //if (Assets.textFont == NULL) {
218 //}
219 //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
220 //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
221 uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
222 uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
223 uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
224 uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
225 uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
226 uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
227 uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
228 uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
229 uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
230 uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
231 uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
232 uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
233 uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
234 uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
235 uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
236 uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
237 uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
238
239 for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
240 uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
241 }
242
243 uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
244 }
245
_UI_DrawSides(float x,float y,float w,float h,float size)246 void _UI_DrawSides(float x, float y, float w, float h, float size) {
247 UI_AdjustFrom640( &x, &y, &w, &h );
248 size *= uiInfo.uiDC.xscale;
249 trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
250 trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
251 }
252
_UI_DrawTopBottom(float x,float y,float w,float h,float size)253 void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
254 UI_AdjustFrom640( &x, &y, &w, &h );
255 size *= uiInfo.uiDC.yscale;
256 trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
257 trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
258 }
259 /*
260 ================
261 UI_DrawRect
262
263 Coordinates are 640*480 virtual values
264 =================
265 */
_UI_DrawRect(float x,float y,float width,float height,float size,const float * color)266 void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
267 trap_R_SetColor( color );
268
269 _UI_DrawTopBottom(x, y, width, height, size);
270 _UI_DrawSides(x, y, width, height, size);
271
272 trap_R_SetColor( NULL );
273 }
274
Text_Width(const char * text,float scale,int limit)275 int Text_Width(const char *text, float scale, int limit) {
276 int count,len;
277 float out;
278 glyphInfo_t *glyph;
279 float useScale;
280 const char *s = text;
281 fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
282 if (scale <= ui_smallFont.value) {
283 font = &uiInfo.uiDC.Assets.smallFont;
284 } else if (scale >= ui_bigFont.value) {
285 font = &uiInfo.uiDC.Assets.bigFont;
286 }
287 useScale = scale * font->glyphScale;
288 out = 0;
289 if (text) {
290 len = strlen(text);
291 if (limit > 0 && len > limit) {
292 len = limit;
293 }
294 count = 0;
295 while (s && *s && count < len) {
296 if ( Q_IsColorString(s) ) {
297 s += 2;
298 continue;
299 } else {
300 glyph = &font->glyphs[(int)*s];
301 out += glyph->xSkip;
302 s++;
303 count++;
304 }
305 }
306 }
307 return out * useScale;
308 }
309
Text_Height(const char * text,float scale,int limit)310 int Text_Height(const char *text, float scale, int limit) {
311 int len, count;
312 float max;
313 glyphInfo_t *glyph;
314 float useScale;
315 const char *s = text;
316 fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
317 if (scale <= ui_smallFont.value) {
318 font = &uiInfo.uiDC.Assets.smallFont;
319 } else if (scale >= ui_bigFont.value) {
320 font = &uiInfo.uiDC.Assets.bigFont;
321 }
322 useScale = scale * font->glyphScale;
323 max = 0;
324 if (text) {
325 len = strlen(text);
326 if (limit > 0 && len > limit) {
327 len = limit;
328 }
329 count = 0;
330 while (s && *s && count < len) {
331 if ( Q_IsColorString(s) ) {
332 s += 2;
333 continue;
334 } else {
335 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
336 if (max < glyph->height) {
337 max = glyph->height;
338 }
339 s++;
340 count++;
341 }
342 }
343 }
344 return max * useScale;
345 }
346
Text_PaintChar(float x,float y,float width,float height,float scale,float s,float t,float s2,float t2,qhandle_t hShader)347 void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
348 float w, h;
349 w = width * scale;
350 h = height * scale;
351 UI_AdjustFrom640( &x, &y, &w, &h );
352 trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
353 }
354
Text_Paint(float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit,int style)355 void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
356 int len, count;
357 vec4_t newColor;
358 glyphInfo_t *glyph;
359 float useScale;
360 fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
361 if (scale <= ui_smallFont.value) {
362 font = &uiInfo.uiDC.Assets.smallFont;
363 } else if (scale >= ui_bigFont.value) {
364 font = &uiInfo.uiDC.Assets.bigFont;
365 }
366 useScale = scale * font->glyphScale;
367 if (text) {
368 const char *s = text;
369 trap_R_SetColor( color );
370 memcpy(&newColor[0], &color[0], sizeof(vec4_t));
371 len = strlen(text);
372 if (limit > 0 && len > limit) {
373 len = limit;
374 }
375 count = 0;
376 while (s && *s && count < len) {
377 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
378 //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
379 //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
380 if ( Q_IsColorString( s ) ) {
381 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
382 newColor[3] = color[3];
383 trap_R_SetColor( newColor );
384 s += 2;
385 continue;
386 } else {
387 float yadj = useScale * glyph->top;
388 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
389 int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
390 colorBlack[3] = newColor[3];
391 trap_R_SetColor( colorBlack );
392 Text_PaintChar(x + ofs, y - yadj + ofs,
393 glyph->imageWidth,
394 glyph->imageHeight,
395 useScale,
396 glyph->s,
397 glyph->t,
398 glyph->s2,
399 glyph->t2,
400 glyph->glyph);
401 trap_R_SetColor( newColor );
402 colorBlack[3] = 1.0;
403 }
404 Text_PaintChar(x, y - yadj,
405 glyph->imageWidth,
406 glyph->imageHeight,
407 useScale,
408 glyph->s,
409 glyph->t,
410 glyph->s2,
411 glyph->t2,
412 glyph->glyph);
413
414 x += (glyph->xSkip * useScale) + adjust;
415 s++;
416 count++;
417 }
418 }
419 trap_R_SetColor( NULL );
420 }
421 }
422
Text_PaintWithCursor(float x,float y,float scale,vec4_t color,const char * text,int cursorPos,char cursor,int limit,int style)423 void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
424 int len, count;
425 vec4_t newColor;
426 glyphInfo_t *glyph, *glyph2;
427 float yadj;
428 float useScale;
429 fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
430 if (scale <= ui_smallFont.value) {
431 font = &uiInfo.uiDC.Assets.smallFont;
432 } else if (scale >= ui_bigFont.value) {
433 font = &uiInfo.uiDC.Assets.bigFont;
434 }
435 useScale = scale * font->glyphScale;
436 if (text) {
437 const char *s = text;
438 trap_R_SetColor( color );
439 memcpy(&newColor[0], &color[0], sizeof(vec4_t));
440 len = strlen(text);
441 if (limit > 0 && len > limit) {
442 len = limit;
443 }
444 count = 0;
445 glyph2 = &font->glyphs[ (int) cursor];
446 while (s && *s && count < len) {
447 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
448 //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
449 //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
450 if ( Q_IsColorString( s ) ) {
451 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
452 newColor[3] = color[3];
453 trap_R_SetColor( newColor );
454 s += 2;
455 continue;
456 } else {
457 yadj = useScale * glyph->top;
458 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
459 int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
460 colorBlack[3] = newColor[3];
461 trap_R_SetColor( colorBlack );
462 Text_PaintChar(x + ofs, y - yadj + ofs,
463 glyph->imageWidth,
464 glyph->imageHeight,
465 useScale,
466 glyph->s,
467 glyph->t,
468 glyph->s2,
469 glyph->t2,
470 glyph->glyph);
471 colorBlack[3] = 1.0;
472 trap_R_SetColor( newColor );
473 }
474 Text_PaintChar(x, y - yadj,
475 glyph->imageWidth,
476 glyph->imageHeight,
477 useScale,
478 glyph->s,
479 glyph->t,
480 glyph->s2,
481 glyph->t2,
482 glyph->glyph);
483
484 yadj = useScale * glyph2->top;
485 if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
486 Text_PaintChar(x, y - yadj,
487 glyph2->imageWidth,
488 glyph2->imageHeight,
489 useScale,
490 glyph2->s,
491 glyph2->t,
492 glyph2->s2,
493 glyph2->t2,
494 glyph2->glyph);
495 }
496
497 x += (glyph->xSkip * useScale);
498 s++;
499 count++;
500 }
501 }
502 // need to paint cursor at end of text
503 if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
504 yadj = useScale * glyph2->top;
505 Text_PaintChar(x, y - yadj,
506 glyph2->imageWidth,
507 glyph2->imageHeight,
508 useScale,
509 glyph2->s,
510 glyph2->t,
511 glyph2->s2,
512 glyph2->t2,
513 glyph2->glyph);
514
515 }
516
517 trap_R_SetColor( NULL );
518 }
519 }
520
521
Text_Paint_Limit(float * maxX,float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit)522 static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
523 int len, count;
524 vec4_t newColor;
525 glyphInfo_t *glyph;
526 if (text) {
527 const char *s = text;
528 float max = *maxX;
529 float useScale;
530 fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
531 if (scale <= ui_smallFont.value) {
532 font = &uiInfo.uiDC.Assets.smallFont;
533 } else if (scale > ui_bigFont.value) {
534 font = &uiInfo.uiDC.Assets.bigFont;
535 }
536 useScale = scale * font->glyphScale;
537 trap_R_SetColor( color );
538 len = strlen(text);
539 if (limit > 0 && len > limit) {
540 len = limit;
541 }
542 count = 0;
543 while (s && *s && count < len) {
544 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
545 if ( Q_IsColorString( s ) ) {
546 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
547 newColor[3] = color[3];
548 trap_R_SetColor( newColor );
549 s += 2;
550 continue;
551 } else {
552 float yadj = useScale * glyph->top;
553 if (Text_Width(s, useScale, 1) + x > max) {
554 *maxX = 0;
555 break;
556 }
557 Text_PaintChar(x, y - yadj,
558 glyph->imageWidth,
559 glyph->imageHeight,
560 useScale,
561 glyph->s,
562 glyph->t,
563 glyph->s2,
564 glyph->t2,
565 glyph->glyph);
566 x += (glyph->xSkip * useScale) + adjust;
567 *maxX = x;
568 count++;
569 s++;
570 }
571 }
572 trap_R_SetColor( NULL );
573 }
574
575 }
576
577
UI_ShowPostGame(qboolean newHigh)578 void UI_ShowPostGame(qboolean newHigh) {
579 trap_Cvar_Set ("cg_cameraOrbit", "0");
580 trap_Cvar_Set("cg_thirdPerson", "0");
581 uiInfo.soundHighScore = newHigh;
582 _UI_SetActiveMenu(UIMENU_POSTGAME);
583 }
584 /*
585 =================
586 _UI_Refresh
587 =================
588 */
589
UI_DrawCenteredPic(qhandle_t image,int w,int h)590 void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
591 int x, y;
592 x = (SCREEN_WIDTH - w) / 2;
593 y = (SCREEN_HEIGHT - h) / 2;
594 UI_DrawHandlePic(x, y, w, h, image);
595 }
596
597 int frameCount = 0;
598 int startTime;
599
600 #define UI_FPS_FRAMES 4
_UI_Refresh(int realtime)601 void _UI_Refresh( int realtime )
602 {
603 static int index;
604 static int previousTimes[UI_FPS_FRAMES];
605
606 //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
607 // return;
608 //}
609
610 uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
611 uiInfo.uiDC.realTime = realtime;
612
613 previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
614 index++;
615 if ( index > UI_FPS_FRAMES ) {
616 int i, total;
617 // average multiple frames together to smooth changes out a bit
618 total = 0;
619 for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
620 total += previousTimes[i];
621 }
622 if ( !total ) {
623 total = 1;
624 }
625 uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
626 }
627
628
629
630 UI_UpdateCvars();
631
632 if (Menu_Count() > 0) {
633 // paint all the menus
634 Menu_PaintAll();
635 // refresh server browser list
636 UI_DoServerRefresh();
637 // refresh server status
638 UI_BuildServerStatus(qfalse);
639 // refresh find player list
640 UI_BuildFindPlayerList(qfalse);
641 }
642
643 // draw cursor
644 UI_SetColor( NULL );
645 if (Menu_Count() > 0) {
646 UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
647 }
648
649 #ifndef NDEBUG
650 if (uiInfo.uiDC.debug)
651 {
652 // cursor coordinates
653 //FIXME
654 //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
655 }
656 #endif
657
658 }
659
660 /*
661 =================
662 _UI_Shutdown
663 =================
664 */
_UI_Shutdown(void)665 void _UI_Shutdown( void ) {
666 trap_LAN_SaveCachedServers();
667 }
668
669 char *defaultMenu = NULL;
670
GetMenuBuffer(const char * filename)671 char *GetMenuBuffer(const char *filename) {
672 int len;
673 fileHandle_t f;
674 static char buf[MAX_MENUFILE];
675
676 len = trap_FS_FOpenFile( filename, &f, FS_READ );
677 if ( !f ) {
678 trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
679 return defaultMenu;
680 }
681 if ( len >= MAX_MENUFILE ) {
682 trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
683 trap_FS_FCloseFile( f );
684 return defaultMenu;
685 }
686
687 trap_FS_Read( buf, len, f );
688 buf[len] = 0;
689 trap_FS_FCloseFile( f );
690 //COM_Compress(buf);
691 return buf;
692
693 }
694
Asset_Parse(int handle)695 qboolean Asset_Parse(int handle) {
696 pc_token_t token;
697 const char *tempStr;
698
699 if (!trap_PC_ReadToken(handle, &token))
700 return qfalse;
701 if (Q_stricmp(token.string, "{") != 0) {
702 return qfalse;
703 }
704
705 while ( 1 ) {
706
707 memset(&token, 0, sizeof(pc_token_t));
708
709 if (!trap_PC_ReadToken(handle, &token))
710 return qfalse;
711
712 if (Q_stricmp(token.string, "}") == 0) {
713 return qtrue;
714 }
715
716 // font
717 if (Q_stricmp(token.string, "font") == 0) {
718 int pointSize;
719 if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
720 return qfalse;
721 }
722 trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
723 uiInfo.uiDC.Assets.fontRegistered = qtrue;
724 continue;
725 }
726
727 if (Q_stricmp(token.string, "smallFont") == 0) {
728 int pointSize;
729 if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
730 return qfalse;
731 }
732 trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
733 continue;
734 }
735
736 if (Q_stricmp(token.string, "bigFont") == 0) {
737 int pointSize;
738 if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
739 return qfalse;
740 }
741 trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
742 continue;
743 }
744
745
746 // gradientbar
747 if (Q_stricmp(token.string, "gradientbar") == 0) {
748 if (!PC_String_Parse(handle, &tempStr)) {
749 return qfalse;
750 }
751 uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
752 continue;
753 }
754
755 // enterMenuSound
756 if (Q_stricmp(token.string, "menuEnterSound") == 0) {
757 if (!PC_String_Parse(handle, &tempStr)) {
758 return qfalse;
759 }
760 uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
761 continue;
762 }
763
764 // exitMenuSound
765 if (Q_stricmp(token.string, "menuExitSound") == 0) {
766 if (!PC_String_Parse(handle, &tempStr)) {
767 return qfalse;
768 }
769 uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
770 continue;
771 }
772
773 // itemFocusSound
774 if (Q_stricmp(token.string, "itemFocusSound") == 0) {
775 if (!PC_String_Parse(handle, &tempStr)) {
776 return qfalse;
777 }
778 uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
779 continue;
780 }
781
782 // menuBuzzSound
783 if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
784 if (!PC_String_Parse(handle, &tempStr)) {
785 return qfalse;
786 }
787 uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
788 continue;
789 }
790
791 if (Q_stricmp(token.string, "cursor") == 0) {
792 if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
793 return qfalse;
794 }
795 uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
796 continue;
797 }
798
799 if (Q_stricmp(token.string, "fadeClamp") == 0) {
800 if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
801 return qfalse;
802 }
803 continue;
804 }
805
806 if (Q_stricmp(token.string, "fadeCycle") == 0) {
807 if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
808 return qfalse;
809 }
810 continue;
811 }
812
813 if (Q_stricmp(token.string, "fadeAmount") == 0) {
814 if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
815 return qfalse;
816 }
817 continue;
818 }
819
820 if (Q_stricmp(token.string, "shadowX") == 0) {
821 if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
822 return qfalse;
823 }
824 continue;
825 }
826
827 if (Q_stricmp(token.string, "shadowY") == 0) {
828 if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
829 return qfalse;
830 }
831 continue;
832 }
833
834 if (Q_stricmp(token.string, "shadowColor") == 0) {
835 if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
836 return qfalse;
837 }
838 uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
839 continue;
840 }
841
842 }
843 return qfalse;
844 }
845
Font_Report(void)846 void Font_Report( void ) {
847 int i;
848 Com_Printf("Font Info\n");
849 Com_Printf("=========\n");
850 for ( i = 32; i < 96; i++) {
851 Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
852 }
853 }
854
UI_Report(void)855 void UI_Report( void ) {
856 String_Report();
857 //Font_Report();
858
859 }
860
UI_ParseMenu(const char * menuFile)861 void UI_ParseMenu(const char *menuFile) {
862 int handle;
863 pc_token_t token;
864
865 Com_Printf("Parsing menu file:%s\n", menuFile);
866
867 handle = trap_PC_LoadSource(menuFile);
868 if (!handle) {
869 return;
870 }
871
872 while ( 1 ) {
873 memset(&token, 0, sizeof(pc_token_t));
874 if (!trap_PC_ReadToken( handle, &token )) {
875 break;
876 }
877
878 //if ( Q_stricmp( token, "{" ) ) {
879 // Com_Printf( "Missing { in menu file\n" );
880 // break;
881 //}
882
883 //if ( menuCount == MAX_MENUS ) {
884 // Com_Printf( "Too many menus!\n" );
885 // break;
886 //}
887
888 if ( token.string[0] == '}' ) {
889 break;
890 }
891
892 if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
893 if (Asset_Parse(handle)) {
894 continue;
895 } else {
896 break;
897 }
898 }
899
900 if (Q_stricmp(token.string, "menudef") == 0) {
901 // start a new menu
902 Menu_New(handle);
903 }
904 }
905 trap_PC_FreeSource(handle);
906 }
907
Load_Menu(int handle)908 qboolean Load_Menu(int handle) {
909 pc_token_t token;
910
911 if (!trap_PC_ReadToken(handle, &token))
912 return qfalse;
913 if (token.string[0] != '{') {
914 return qfalse;
915 }
916
917 while ( 1 ) {
918
919 if (!trap_PC_ReadToken(handle, &token))
920 return qfalse;
921
922 if ( token.string[0] == 0 ) {
923 return qfalse;
924 }
925
926 if ( token.string[0] == '}' ) {
927 return qtrue;
928 }
929
930 UI_ParseMenu(token.string);
931 }
932 return qfalse;
933 }
934
UI_LoadMenus(const char * menuFile,qboolean reset)935 void UI_LoadMenus(const char *menuFile, qboolean reset) {
936 pc_token_t token;
937 int handle;
938 int start;
939
940 start = trap_Milliseconds();
941
942 handle = trap_PC_LoadSource( menuFile );
943 if (!handle) {
944 trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
945 handle = trap_PC_LoadSource( "ui/menus.txt" );
946 if (!handle) {
947 trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n") );
948 }
949 }
950
951 ui_new.integer = 1;
952
953 if (reset) {
954 Menu_Reset();
955 }
956
957 while ( 1 ) {
958 if (!trap_PC_ReadToken(handle, &token))
959 break;
960 if( token.string[0] == 0 || token.string[0] == '}') {
961 break;
962 }
963
964 if ( token.string[0] == '}' ) {
965 break;
966 }
967
968 if (Q_stricmp(token.string, "loadmenu") == 0) {
969 if (Load_Menu(handle)) {
970 continue;
971 } else {
972 break;
973 }
974 }
975 }
976
977 Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
978
979 trap_PC_FreeSource( handle );
980 }
981
UI_Load(void)982 void UI_Load(void) {
983 char lastName[1024];
984 menuDef_t *menu = Menu_GetFocused();
985 char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
986 if (menu && menu->window.name) {
987 strcpy(lastName, menu->window.name);
988 }
989 if (menuSet == NULL || menuSet[0] == '\0') {
990 menuSet = "ui/menus.txt";
991 }
992
993 String_Init();
994
995 #ifdef PRE_RELEASE_TADEMO
996 UI_ParseGameInfo("demogameinfo.txt");
997 #else
998 UI_ParseGameInfo("gameinfo.txt");
999 UI_LoadArenas();
1000 #endif
1001
1002 UI_LoadMenus(menuSet, qtrue);
1003 Menus_CloseAll();
1004 Menus_ActivateByName(lastName);
1005
1006 }
1007
1008 static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
1009 #ifndef MISSIONPACK
1010 static int numHandicaps = sizeof(handicapValues) / sizeof(const char*);
1011 #endif
1012
UI_DrawHandicap(rectDef_t * rect,float scale,vec4_t color,int textStyle)1013 static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1014 int i, h;
1015
1016 h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
1017 i = 20 - h / 5;
1018
1019 Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
1020 }
1021
UI_DrawClanName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1022 static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1023 Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
1024 }
1025
1026
UI_SetCapFragLimits(qboolean uiVars)1027 static void UI_SetCapFragLimits(qboolean uiVars) {
1028 int cap = 5;
1029 int frag = 10;
1030 if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
1031 cap = 4;
1032 } else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
1033 cap = 15;
1034 }
1035 if (uiVars) {
1036 trap_Cvar_Set("ui_captureLimit", va("%d", cap));
1037 trap_Cvar_Set("ui_fragLimit", va("%d", frag));
1038 } else {
1039 trap_Cvar_Set("capturelimit", va("%d", cap));
1040 trap_Cvar_Set("fraglimit", va("%d", frag));
1041 }
1042 }
1043 // ui_gameType assumes gametype 0 is -1 ALL and will not show
UI_DrawGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1044 static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1045 Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
1046 }
1047
UI_DrawNetGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1048 static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1049 if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
1050 trap_Cvar_Set("ui_netGameType", "0");
1051 trap_Cvar_Set("ui_actualNetGameType", "0");
1052 }
1053 Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
1054 }
1055
UI_DrawJoinGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1056 static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1057 if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
1058 trap_Cvar_Set("ui_joinGameType", "0");
1059 }
1060 Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
1061 }
1062
1063
1064
UI_TeamIndexFromName(const char * name)1065 static int UI_TeamIndexFromName(const char *name) {
1066 int i;
1067
1068 if (name && *name) {
1069 for (i = 0; i < uiInfo.teamCount; i++) {
1070 if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
1071 return i;
1072 }
1073 }
1074 }
1075
1076 return 0;
1077
1078 }
1079
UI_DrawClanLogo(rectDef_t * rect,float scale,vec4_t color)1080 static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
1081 int i;
1082 i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1083 if (i >= 0 && i < uiInfo.teamCount) {
1084 trap_R_SetColor( color );
1085
1086 if (uiInfo.teamList[i].teamIcon == -1) {
1087 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1088 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1089 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1090 }
1091
1092 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
1093 trap_R_SetColor(NULL);
1094 }
1095 }
1096
UI_DrawClanCinematic(rectDef_t * rect,float scale,vec4_t color)1097 static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
1098 int i;
1099 i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1100 if (i >= 0 && i < uiInfo.teamCount) {
1101
1102 if (uiInfo.teamList[i].cinematic >= -2) {
1103 if (uiInfo.teamList[i].cinematic == -1) {
1104 uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1105 }
1106 if (uiInfo.teamList[i].cinematic >= 0) {
1107 trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
1108 trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
1109 trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
1110 } else {
1111 trap_R_SetColor( color );
1112 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
1113 trap_R_SetColor(NULL);
1114 uiInfo.teamList[i].cinematic = -2;
1115 }
1116 } else {
1117 trap_R_SetColor( color );
1118 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
1119 trap_R_SetColor(NULL);
1120 }
1121 }
1122
1123 }
1124
UI_DrawPreviewCinematic(rectDef_t * rect,float scale,vec4_t color)1125 static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
1126 if (uiInfo.previewMovie > -2) {
1127 uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1128 if (uiInfo.previewMovie >= 0) {
1129 trap_CIN_RunCinematic(uiInfo.previewMovie);
1130 trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
1131 trap_CIN_DrawCinematic(uiInfo.previewMovie);
1132 } else {
1133 uiInfo.previewMovie = -2;
1134 }
1135 }
1136
1137 }
1138
1139
1140
UI_DrawSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)1141 static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1142 int i;
1143 i = trap_Cvar_VariableValue( "g_spSkill" );
1144 if (i < 1 || i > numSkillLevels) {
1145 i = 1;
1146 }
1147 Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
1148 }
1149
1150
UI_DrawTeamName(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int textStyle)1151 static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
1152 int i;
1153 i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
1154 if (i >= 0 && i < uiInfo.teamCount) {
1155 Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
1156 }
1157 }
1158
UI_DrawTeamMember(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int num,int textStyle)1159 static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
1160 // 0 - None
1161 // 1 - Human
1162 // 2..NumCharacters - Bot
1163 int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
1164 const char *text;
1165 if (value <= 0) {
1166 text = "Closed";
1167 } else if (value == 1) {
1168 text = "Human";
1169 } else {
1170 value -= 2;
1171
1172 if (ui_actualNetGameType.integer >= GT_TEAM) {
1173 if (value >= uiInfo.characterCount) {
1174 value = 0;
1175 }
1176 text = uiInfo.characterList[value].name;
1177 } else {
1178 if (value >= UI_GetNumBots()) {
1179 value = 0;
1180 }
1181 text = UI_GetBotNameByNumber(value);
1182 }
1183 }
1184 Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
1185 }
1186
UI_DrawEffects(rectDef_t * rect,float scale,vec4_t color)1187 static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
1188 UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
1189 UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
1190 }
1191
UI_DrawMapPreview(rectDef_t * rect,float scale,vec4_t color,qboolean net)1192 static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
1193 int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1194 if (map < 0 || map > uiInfo.mapCount) {
1195 if (net) {
1196 ui_currentNetMap.integer = 0;
1197 trap_Cvar_Set("ui_currentNetMap", "0");
1198 } else {
1199 ui_currentMap.integer = 0;
1200 trap_Cvar_Set("ui_currentMap", "0");
1201 }
1202 map = 0;
1203 }
1204
1205 if (uiInfo.mapList[map].levelShot == -1) {
1206 uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
1207 }
1208
1209 if (uiInfo.mapList[map].levelShot > 0) {
1210 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
1211 } else {
1212 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
1213 }
1214 }
1215
1216
UI_DrawMapTimeToBeat(rectDef_t * rect,float scale,vec4_t color,int textStyle)1217 static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1218 int minutes, seconds, time;
1219 if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
1220 ui_currentMap.integer = 0;
1221 trap_Cvar_Set("ui_currentMap", "0");
1222 }
1223
1224 time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
1225
1226 minutes = time / 60;
1227 seconds = time % 60;
1228
1229 Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
1230 }
1231
1232
1233
UI_DrawMapCinematic(rectDef_t * rect,float scale,vec4_t color,qboolean net)1234 static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
1235
1236 int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1237 if (map < 0 || map > uiInfo.mapCount) {
1238 if (net) {
1239 ui_currentNetMap.integer = 0;
1240 trap_Cvar_Set("ui_currentNetMap", "0");
1241 } else {
1242 ui_currentMap.integer = 0;
1243 trap_Cvar_Set("ui_currentMap", "0");
1244 }
1245 map = 0;
1246 }
1247
1248 if (uiInfo.mapList[map].cinematic >= -1) {
1249 if (uiInfo.mapList[map].cinematic == -1) {
1250 uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1251 }
1252 if (uiInfo.mapList[map].cinematic >= 0) {
1253 trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
1254 trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
1255 trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
1256 } else {
1257 uiInfo.mapList[map].cinematic = -2;
1258 }
1259 } else {
1260 UI_DrawMapPreview(rect, scale, color, net);
1261 }
1262 }
1263
1264
1265
1266 static qboolean updateModel = qtrue;
1267 static qboolean q3Model = qfalse;
1268
UI_DrawPlayerModel(rectDef_t * rect)1269 static void UI_DrawPlayerModel(rectDef_t *rect) {
1270 static playerInfo_t info;
1271 char model[MAX_QPATH];
1272 char team[256];
1273 char head[256];
1274 vec3_t viewangles;
1275 vec3_t moveangles;
1276
1277 if (trap_Cvar_VariableValue("ui_Q3Model")) {
1278 strcpy(model, UI_Cvar_VariableString("model"));
1279 strcpy(head, UI_Cvar_VariableString("headmodel"));
1280 if (!q3Model) {
1281 q3Model = qtrue;
1282 updateModel = qtrue;
1283 }
1284 team[0] = '\0';
1285 } else {
1286
1287 strcpy(team, UI_Cvar_VariableString("ui_teamName"));
1288 strcpy(model, UI_Cvar_VariableString("team_model"));
1289 strcpy(head, UI_Cvar_VariableString("team_headmodel"));
1290 if (q3Model) {
1291 q3Model = qfalse;
1292 updateModel = qtrue;
1293 }
1294 }
1295 if (updateModel) {
1296 memset( &info, 0, sizeof(playerInfo_t) );
1297 viewangles[YAW] = 180 - 10;
1298 viewangles[PITCH] = 0;
1299 viewangles[ROLL] = 0;
1300 VectorClear( moveangles );
1301 UI_PlayerInfo_SetModel( &info, model, head, team);
1302 UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
1303 // UI_RegisterClientModelname( &info, model, head, team);
1304 updateModel = qfalse;
1305 }
1306
1307 UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
1308
1309 }
1310
UI_DrawNetSource(rectDef_t * rect,float scale,vec4_t color,int textStyle)1311 static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1312 if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
1313 ui_netSource.integer = 0;
1314 }
1315 Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
1316 }
1317
UI_DrawNetMapPreview(rectDef_t * rect,float scale,vec4_t color)1318 static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
1319
1320 if (uiInfo.serverStatus.currentServerPreview > 0) {
1321 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
1322 } else {
1323 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
1324 }
1325 }
1326
UI_DrawNetMapCinematic(rectDef_t * rect,float scale,vec4_t color)1327 static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
1328 if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
1329 ui_currentNetMap.integer = 0;
1330 trap_Cvar_Set("ui_currentNetMap", "0");
1331 }
1332
1333 if (uiInfo.serverStatus.currentServerCinematic >= 0) {
1334 trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
1335 trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
1336 trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
1337 } else {
1338 UI_DrawNetMapPreview(rect, scale, color);
1339 }
1340 }
1341
1342
1343
UI_DrawNetFilter(rectDef_t * rect,float scale,vec4_t color,int textStyle)1344 static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1345 if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
1346 ui_serverFilterType.integer = 0;
1347 }
1348 Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
1349 }
1350
1351
UI_DrawTier(rectDef_t * rect,float scale,vec4_t color,int textStyle)1352 static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1353 int i;
1354 i = trap_Cvar_VariableValue( "ui_currentTier" );
1355 if (i < 0 || i >= uiInfo.tierCount) {
1356 i = 0;
1357 }
1358 Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
1359 }
1360
UI_DrawTierMap(rectDef_t * rect,int index)1361 static void UI_DrawTierMap(rectDef_t *rect, int index) {
1362 int i;
1363 i = trap_Cvar_VariableValue( "ui_currentTier" );
1364 if (i < 0 || i >= uiInfo.tierCount) {
1365 i = 0;
1366 }
1367
1368 if (uiInfo.tierList[i].mapHandles[index] == -1) {
1369 uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
1370 }
1371
1372 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
1373 }
1374
UI_EnglishMapName(const char * map)1375 static const char *UI_EnglishMapName(const char *map) {
1376 int i;
1377 for (i = 0; i < uiInfo.mapCount; i++) {
1378 if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
1379 return uiInfo.mapList[i].mapName;
1380 }
1381 }
1382 return "";
1383 }
1384
UI_DrawTierMapName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1385 static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1386 int i, j;
1387 i = trap_Cvar_VariableValue( "ui_currentTier" );
1388 if (i < 0 || i >= uiInfo.tierCount) {
1389 i = 0;
1390 }
1391 j = trap_Cvar_VariableValue("ui_currentMap");
1392 if (j < 0 || j > MAPS_PER_TIER) {
1393 j = 0;
1394 }
1395
1396 Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
1397 }
1398
UI_DrawTierGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1399 static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1400 int i, j;
1401 i = trap_Cvar_VariableValue( "ui_currentTier" );
1402 if (i < 0 || i >= uiInfo.tierCount) {
1403 i = 0;
1404 }
1405 j = trap_Cvar_VariableValue("ui_currentMap");
1406 if (j < 0 || j > MAPS_PER_TIER) {
1407 j = 0;
1408 }
1409
1410 Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
1411 }
1412
1413
1414 #ifndef MISSIONPACK
UI_OpponentLeaderName(void)1415 static const char *UI_OpponentLeaderName(void) {
1416 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1417 return uiInfo.teamList[i].teamMembers[0];
1418 }
1419 #endif
1420
UI_AIFromName(const char * name)1421 static const char *UI_AIFromName(const char *name) {
1422 int j;
1423 for (j = 0; j < uiInfo.aliasCount; j++) {
1424 if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
1425 return uiInfo.aliasList[j].ai;
1426 }
1427 }
1428 return "James";
1429 }
1430
1431 #ifndef MISSIONPACK
UI_AIIndex(const char * name)1432 static const int UI_AIIndex(const char *name) {
1433 int j;
1434 for (j = 0; j < uiInfo.characterCount; j++) {
1435 if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
1436 return j;
1437 }
1438 }
1439 return 0;
1440 }
1441 #endif
1442
1443 #ifndef MISSIONPACK
UI_AIIndexFromName(const char * name)1444 static const int UI_AIIndexFromName(const char *name) {
1445 int j;
1446 for (j = 0; j < uiInfo.aliasCount; j++) {
1447 if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
1448 return UI_AIIndex(uiInfo.aliasList[j].ai);
1449 }
1450 }
1451 return 0;
1452 }
1453 #endif
1454
1455
1456 #ifndef MISSIONPACK
UI_OpponentLeaderHead(void)1457 static const char *UI_OpponentLeaderHead(void) {
1458 const char *leader = UI_OpponentLeaderName();
1459 return UI_AIFromName(leader);
1460 }
1461 #endif
1462
1463 #ifndef MISSIONPACK
UI_OpponentLeaderModel(void)1464 static const char *UI_OpponentLeaderModel(void) {
1465 int i;
1466 const char *head = UI_OpponentLeaderHead();
1467 for (i = 0; i < uiInfo.characterCount; i++) {
1468 if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
1469 return uiInfo.characterList[i].base;
1470 }
1471 }
1472 return "James";
1473 }
1474 #endif
1475
1476
1477 static qboolean updateOpponentModel = qtrue;
UI_DrawOpponent(rectDef_t * rect)1478 static void UI_DrawOpponent(rectDef_t *rect) {
1479 static playerInfo_t info2;
1480 char model[MAX_QPATH];
1481 char headmodel[MAX_QPATH];
1482 char team[256];
1483 vec3_t viewangles;
1484 vec3_t moveangles;
1485
1486 if (updateOpponentModel) {
1487
1488 strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
1489 strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
1490 team[0] = '\0';
1491
1492 memset( &info2, 0, sizeof(playerInfo_t) );
1493 viewangles[YAW] = 180 - 10;
1494 viewangles[PITCH] = 0;
1495 viewangles[ROLL] = 0;
1496 VectorClear( moveangles );
1497 UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
1498 UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
1499 UI_RegisterClientModelname( &info2, model, headmodel, team);
1500 updateOpponentModel = qfalse;
1501 }
1502
1503 UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
1504
1505 }
1506
UI_NextOpponent(void)1507 static void UI_NextOpponent( void ) {
1508 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1509 int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1510 i++;
1511 if (i >= uiInfo.teamCount) {
1512 i = 0;
1513 }
1514 if (i == j) {
1515 i++;
1516 if ( i >= uiInfo.teamCount) {
1517 i = 0;
1518 }
1519 }
1520 trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
1521 }
1522
UI_PriorOpponent(void)1523 static void UI_PriorOpponent( void ) {
1524 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1525 int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1526 i--;
1527 if (i < 0) {
1528 i = uiInfo.teamCount - 1;
1529 }
1530 if (i == j) {
1531 i--;
1532 if ( i < 0) {
1533 i = uiInfo.teamCount - 1;
1534 }
1535 }
1536 trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
1537 }
1538
UI_DrawPlayerLogo(rectDef_t * rect,vec3_t color)1539 static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
1540 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1541
1542 if (uiInfo.teamList[i].teamIcon == -1) {
1543 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1544 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1545 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1546 }
1547
1548 trap_R_SetColor( color );
1549 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1550 trap_R_SetColor( NULL );
1551 }
1552
UI_DrawPlayerLogoMetal(rectDef_t * rect,vec3_t color)1553 static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
1554 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1555 if (uiInfo.teamList[i].teamIcon == -1) {
1556 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1557 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1558 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1559 }
1560
1561 trap_R_SetColor( color );
1562 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
1563 trap_R_SetColor( NULL );
1564 }
1565
UI_DrawPlayerLogoName(rectDef_t * rect,vec3_t color)1566 static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
1567 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1568 if (uiInfo.teamList[i].teamIcon == -1) {
1569 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1570 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1571 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1572 }
1573
1574 trap_R_SetColor( color );
1575 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
1576 trap_R_SetColor( NULL );
1577 }
1578
UI_DrawOpponentLogo(rectDef_t * rect,vec3_t color)1579 static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
1580 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1581 if (uiInfo.teamList[i].teamIcon == -1) {
1582 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1583 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1584 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1585 }
1586
1587 trap_R_SetColor( color );
1588 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1589 trap_R_SetColor( NULL );
1590 }
1591
UI_DrawOpponentLogoMetal(rectDef_t * rect,vec3_t color)1592 static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
1593 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1594 if (uiInfo.teamList[i].teamIcon == -1) {
1595 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1596 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1597 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1598 }
1599
1600 trap_R_SetColor( color );
1601 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
1602 trap_R_SetColor( NULL );
1603 }
1604
UI_DrawOpponentLogoName(rectDef_t * rect,vec3_t color)1605 static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
1606 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1607 if (uiInfo.teamList[i].teamIcon == -1) {
1608 uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1609 uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1610 uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1611 }
1612
1613 trap_R_SetColor( color );
1614 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
1615 trap_R_SetColor( NULL );
1616 }
1617
UI_DrawAllMapsSelection(rectDef_t * rect,float scale,vec4_t color,int textStyle,qboolean net)1618 static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
1619 int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1620 if (map >= 0 && map < uiInfo.mapCount) {
1621 Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
1622 }
1623 }
1624
UI_DrawOpponentName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1625 static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1626 Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
1627 }
1628
1629
UI_OwnerDrawWidth(int ownerDraw,float scale)1630 static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
1631 int i, h, value;
1632 const char *text;
1633 const char *s = NULL;
1634
1635 switch (ownerDraw) {
1636 case UI_HANDICAP:
1637 h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
1638 i = 20 - h / 5;
1639 s = handicapValues[i];
1640 break;
1641 case UI_CLANNAME:
1642 s = UI_Cvar_VariableString("ui_teamName");
1643 break;
1644 case UI_GAMETYPE:
1645 s = uiInfo.gameTypes[ui_gameType.integer].gameType;
1646 break;
1647 case UI_SKILL:
1648 i = trap_Cvar_VariableValue( "g_spSkill" );
1649 if (i < 1 || i > numSkillLevels) {
1650 i = 1;
1651 }
1652 s = skillLevels[i-1];
1653 break;
1654 case UI_BLUETEAMNAME:
1655 i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
1656 if (i >= 0 && i < uiInfo.teamCount) {
1657 s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
1658 }
1659 break;
1660 case UI_REDTEAMNAME:
1661 i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
1662 if (i >= 0 && i < uiInfo.teamCount) {
1663 s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
1664 }
1665 break;
1666 case UI_BLUETEAM1:
1667 case UI_BLUETEAM2:
1668 case UI_BLUETEAM3:
1669 case UI_BLUETEAM4:
1670 case UI_BLUETEAM5:
1671 value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
1672 if (value <= 0) {
1673 text = "Closed";
1674 } else if (value == 1) {
1675 text = "Human";
1676 } else {
1677 value -= 2;
1678 if (value >= uiInfo.aliasCount) {
1679 value = 0;
1680 }
1681 text = uiInfo.aliasList[value].name;
1682 }
1683 s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
1684 break;
1685 case UI_REDTEAM1:
1686 case UI_REDTEAM2:
1687 case UI_REDTEAM3:
1688 case UI_REDTEAM4:
1689 case UI_REDTEAM5:
1690 value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
1691 if (value <= 0) {
1692 text = "Closed";
1693 } else if (value == 1) {
1694 text = "Human";
1695 } else {
1696 value -= 2;
1697 if (value >= uiInfo.aliasCount) {
1698 value = 0;
1699 }
1700 text = uiInfo.aliasList[value].name;
1701 }
1702 s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
1703 break;
1704 case UI_NETSOURCE:
1705 if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
1706 ui_netSource.integer = 0;
1707 }
1708 s = va("Source: %s", netSources[ui_netSource.integer]);
1709 break;
1710 case UI_NETFILTER:
1711 if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
1712 ui_serverFilterType.integer = 0;
1713 }
1714 s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
1715 break;
1716 case UI_TIER:
1717 break;
1718 case UI_TIER_MAPNAME:
1719 break;
1720 case UI_TIER_GAMETYPE:
1721 break;
1722 case UI_ALLMAPS_SELECTION:
1723 break;
1724 case UI_OPPONENT_NAME:
1725 break;
1726 case UI_KEYBINDSTATUS:
1727 if (Display_KeyBindPending()) {
1728 s = "Waiting for new key... Press ESCAPE to cancel";
1729 } else {
1730 s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
1731 }
1732 break;
1733 case UI_SERVERREFRESHDATE:
1734 s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
1735 break;
1736 default:
1737 break;
1738 }
1739
1740 if (s) {
1741 return Text_Width(s, scale, 0);
1742 }
1743 return 0;
1744 }
1745
UI_DrawBotName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1746 static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1747 int value = uiInfo.botIndex;
1748 int game = trap_Cvar_VariableValue("g_gametype");
1749 const char *text = "";
1750 if (game >= GT_TEAM) {
1751 if (value >= uiInfo.characterCount) {
1752 value = 0;
1753 }
1754 text = uiInfo.characterList[value].name;
1755 } else {
1756 if (value >= UI_GetNumBots()) {
1757 value = 0;
1758 }
1759 text = UI_GetBotNameByNumber(value);
1760 }
1761 Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
1762 }
1763
UI_DrawBotSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)1764 static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1765 if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
1766 Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
1767 }
1768 }
1769
UI_DrawRedBlue(rectDef_t * rect,float scale,vec4_t color,int textStyle)1770 static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1771 Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
1772 }
1773
UI_DrawCrosshair(rectDef_t * rect,float scale,vec4_t color)1774 static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
1775 trap_R_SetColor( color );
1776 if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
1777 uiInfo.currentCrosshair = 0;
1778 }
1779 UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
1780 trap_R_SetColor( NULL );
1781 }
1782
1783 /*
1784 ===============
1785 UI_BuildPlayerList
1786 ===============
1787 */
UI_BuildPlayerList(void)1788 static void UI_BuildPlayerList( void ) {
1789 uiClientState_t cs;
1790 int n, count, team, team2, playerTeamNumber;
1791 char info[MAX_INFO_STRING];
1792
1793 trap_GetClientState( &cs );
1794 trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
1795 uiInfo.playerNumber = cs.clientNum;
1796 uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
1797 team = atoi(Info_ValueForKey(info, "t"));
1798 trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
1799 count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
1800 uiInfo.playerCount = 0;
1801 uiInfo.myTeamCount = 0;
1802 playerTeamNumber = 0;
1803 for( n = 0; n < count; n++ ) {
1804 trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
1805
1806 if (info[0]) {
1807 Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
1808 Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
1809 uiInfo.playerCount++;
1810 team2 = atoi(Info_ValueForKey(info, "t"));
1811 if (team2 == team) {
1812 Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
1813 Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
1814 uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
1815 if (uiInfo.playerNumber == n) {
1816 playerTeamNumber = uiInfo.myTeamCount;
1817 }
1818 uiInfo.myTeamCount++;
1819 }
1820 }
1821 }
1822
1823 if (!uiInfo.teamLeader) {
1824 trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
1825 }
1826
1827 n = trap_Cvar_VariableValue("cg_selectedPlayer");
1828 if (n < 0 || n > uiInfo.myTeamCount) {
1829 n = 0;
1830 }
1831 if (n < uiInfo.myTeamCount) {
1832 trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
1833 }
1834 }
1835
1836
UI_DrawSelectedPlayer(rectDef_t * rect,float scale,vec4_t color,int textStyle)1837 static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1838 if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
1839 uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
1840 UI_BuildPlayerList();
1841 }
1842 Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
1843 }
1844
UI_DrawServerRefreshDate(rectDef_t * rect,float scale,vec4_t color,int textStyle)1845 static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1846 if (uiInfo.serverStatus.refreshActive) {
1847 vec4_t lowLight, newColor;
1848 lowLight[0] = 0.8 * color[0];
1849 lowLight[1] = 0.8 * color[1];
1850 lowLight[2] = 0.8 * color[2];
1851 lowLight[3] = 0.8 * color[3];
1852 LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
1853 Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
1854 } else {
1855 char buff[64];
1856 Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
1857 Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
1858 }
1859 }
1860
UI_DrawServerMOTD(rectDef_t * rect,float scale,vec4_t color)1861 static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
1862 if (uiInfo.serverStatus.motdLen) {
1863 float maxX;
1864
1865 if (uiInfo.serverStatus.motdWidth == -1) {
1866 uiInfo.serverStatus.motdWidth = 0;
1867 uiInfo.serverStatus.motdPaintX = rect->x + 1;
1868 uiInfo.serverStatus.motdPaintX2 = -1;
1869 }
1870
1871 if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
1872 uiInfo.serverStatus.motdOffset = 0;
1873 uiInfo.serverStatus.motdPaintX = rect->x + 1;
1874 uiInfo.serverStatus.motdPaintX2 = -1;
1875 }
1876
1877 if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
1878 uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
1879 if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
1880 if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
1881 uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
1882 uiInfo.serverStatus.motdOffset++;
1883 } else {
1884 uiInfo.serverStatus.motdOffset = 0;
1885 if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1886 uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
1887 } else {
1888 uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
1889 }
1890 uiInfo.serverStatus.motdPaintX2 = -1;
1891 }
1892 } else {
1893 //serverStatus.motdPaintX--;
1894 uiInfo.serverStatus.motdPaintX -= 2;
1895 if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1896 //serverStatus.motdPaintX2--;
1897 uiInfo.serverStatus.motdPaintX2 -= 2;
1898 }
1899 }
1900 }
1901
1902 maxX = rect->x + rect->w - 2;
1903 Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
1904 if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1905 float maxX2 = rect->x + rect->w - 2;
1906 Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
1907 }
1908 if (uiInfo.serverStatus.motdOffset && maxX > 0) {
1909 // if we have an offset ( we are skipping the first part of the string ) and we fit the string
1910 if (uiInfo.serverStatus.motdPaintX2 == -1) {
1911 uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
1912 }
1913 } else {
1914 uiInfo.serverStatus.motdPaintX2 = -1;
1915 }
1916
1917 }
1918 }
1919
UI_DrawKeyBindStatus(rectDef_t * rect,float scale,vec4_t color,int textStyle)1920 static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1921 // int ofs = 0; TTimo: unused
1922 if (Display_KeyBindPending()) {
1923 Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
1924 } else {
1925 Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
1926 }
1927 }
1928
UI_DrawGLInfo(rectDef_t * rect,float scale,vec4_t color,int textStyle)1929 static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1930 char * eptr;
1931 char buff[1024];
1932 const char *lines[64];
1933 int y, numLines, i;
1934
1935 Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
1936 Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle);
1937 Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle);
1938
1939 // build null terminated extension strings
1940 // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
1941 // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
1942 // brought down the string size to 1024, there's not much that can be shown on the screen anyway
1943 Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
1944 eptr = buff;
1945 y = rect->y + 45;
1946 numLines = 0;
1947 while ( y < rect->y + rect->h && *eptr )
1948 {
1949 while ( *eptr && *eptr == ' ' )
1950 *eptr++ = '\0';
1951
1952 // track start of valid string
1953 if (*eptr && *eptr != ' ') {
1954 lines[numLines++] = eptr;
1955 }
1956
1957 while ( *eptr && *eptr != ' ' )
1958 eptr++;
1959 }
1960
1961 i = 0;
1962 while (i < numLines) {
1963 Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
1964 if (i < numLines) {
1965 Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
1966 }
1967 y += 10;
1968 if (y > rect->y + rect->h - 11) {
1969 break;
1970 }
1971 }
1972
1973
1974 }
1975
1976 // FIXME: table drive
1977 //
UI_OwnerDraw(float x,float y,float w,float h,float text_x,float text_y,int ownerDraw,int ownerDrawFlags,int align,float special,float scale,vec4_t color,qhandle_t shader,int textStyle)1978 static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
1979 rectDef_t rect;
1980
1981 rect.x = x + text_x;
1982 rect.y = y + text_y;
1983 rect.w = w;
1984 rect.h = h;
1985
1986 switch (ownerDraw) {
1987 case UI_HANDICAP:
1988 UI_DrawHandicap(&rect, scale, color, textStyle);
1989 break;
1990 case UI_EFFECTS:
1991 UI_DrawEffects(&rect, scale, color);
1992 break;
1993 case UI_PLAYERMODEL:
1994 UI_DrawPlayerModel(&rect);
1995 break;
1996 case UI_CLANNAME:
1997 UI_DrawClanName(&rect, scale, color, textStyle);
1998 break;
1999 case UI_CLANLOGO:
2000 UI_DrawClanLogo(&rect, scale, color);
2001 break;
2002 case UI_CLANCINEMATIC:
2003 UI_DrawClanCinematic(&rect, scale, color);
2004 break;
2005 case UI_PREVIEWCINEMATIC:
2006 UI_DrawPreviewCinematic(&rect, scale, color);
2007 break;
2008 case UI_GAMETYPE:
2009 UI_DrawGameType(&rect, scale, color, textStyle);
2010 break;
2011 case UI_NETGAMETYPE:
2012 UI_DrawNetGameType(&rect, scale, color, textStyle);
2013 break;
2014 case UI_JOINGAMETYPE:
2015 UI_DrawJoinGameType(&rect, scale, color, textStyle);
2016 break;
2017 case UI_MAPPREVIEW:
2018 UI_DrawMapPreview(&rect, scale, color, qtrue);
2019 break;
2020 case UI_MAP_TIMETOBEAT:
2021 UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
2022 break;
2023 case UI_MAPCINEMATIC:
2024 UI_DrawMapCinematic(&rect, scale, color, qfalse);
2025 break;
2026 case UI_STARTMAPCINEMATIC:
2027 UI_DrawMapCinematic(&rect, scale, color, qtrue);
2028 break;
2029 case UI_SKILL:
2030 UI_DrawSkill(&rect, scale, color, textStyle);
2031 break;
2032 case UI_BLUETEAMNAME:
2033 UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
2034 break;
2035 case UI_REDTEAMNAME:
2036 UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
2037 break;
2038 case UI_BLUETEAM1:
2039 case UI_BLUETEAM2:
2040 case UI_BLUETEAM3:
2041 case UI_BLUETEAM4:
2042 case UI_BLUETEAM5:
2043 UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
2044 break;
2045 case UI_REDTEAM1:
2046 case UI_REDTEAM2:
2047 case UI_REDTEAM3:
2048 case UI_REDTEAM4:
2049 case UI_REDTEAM5:
2050 UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
2051 break;
2052 case UI_NETSOURCE:
2053 UI_DrawNetSource(&rect, scale, color, textStyle);
2054 break;
2055 case UI_NETMAPPREVIEW:
2056 UI_DrawNetMapPreview(&rect, scale, color);
2057 break;
2058 case UI_NETMAPCINEMATIC:
2059 UI_DrawNetMapCinematic(&rect, scale, color);
2060 break;
2061 case UI_NETFILTER:
2062 UI_DrawNetFilter(&rect, scale, color, textStyle);
2063 break;
2064 case UI_TIER:
2065 UI_DrawTier(&rect, scale, color, textStyle);
2066 break;
2067 case UI_OPPONENTMODEL:
2068 UI_DrawOpponent(&rect);
2069 break;
2070 case UI_TIERMAP1:
2071 UI_DrawTierMap(&rect, 0);
2072 break;
2073 case UI_TIERMAP2:
2074 UI_DrawTierMap(&rect, 1);
2075 break;
2076 case UI_TIERMAP3:
2077 UI_DrawTierMap(&rect, 2);
2078 break;
2079 case UI_PLAYERLOGO:
2080 UI_DrawPlayerLogo(&rect, color);
2081 break;
2082 case UI_PLAYERLOGO_METAL:
2083 UI_DrawPlayerLogoMetal(&rect, color);
2084 break;
2085 case UI_PLAYERLOGO_NAME:
2086 UI_DrawPlayerLogoName(&rect, color);
2087 break;
2088 case UI_OPPONENTLOGO:
2089 UI_DrawOpponentLogo(&rect, color);
2090 break;
2091 case UI_OPPONENTLOGO_METAL:
2092 UI_DrawOpponentLogoMetal(&rect, color);
2093 break;
2094 case UI_OPPONENTLOGO_NAME:
2095 UI_DrawOpponentLogoName(&rect, color);
2096 break;
2097 case UI_TIER_MAPNAME:
2098 UI_DrawTierMapName(&rect, scale, color, textStyle);
2099 break;
2100 case UI_TIER_GAMETYPE:
2101 UI_DrawTierGameType(&rect, scale, color, textStyle);
2102 break;
2103 case UI_ALLMAPS_SELECTION:
2104 UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
2105 break;
2106 case UI_MAPS_SELECTION:
2107 UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
2108 break;
2109 case UI_OPPONENT_NAME:
2110 UI_DrawOpponentName(&rect, scale, color, textStyle);
2111 break;
2112 case UI_BOTNAME:
2113 UI_DrawBotName(&rect, scale, color, textStyle);
2114 break;
2115 case UI_BOTSKILL:
2116 UI_DrawBotSkill(&rect, scale, color, textStyle);
2117 break;
2118 case UI_REDBLUE:
2119 UI_DrawRedBlue(&rect, scale, color, textStyle);
2120 break;
2121 case UI_CROSSHAIR:
2122 UI_DrawCrosshair(&rect, scale, color);
2123 break;
2124 case UI_SELECTEDPLAYER:
2125 UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
2126 break;
2127 case UI_SERVERREFRESHDATE:
2128 UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
2129 break;
2130 case UI_SERVERMOTD:
2131 UI_DrawServerMOTD(&rect, scale, color);
2132 break;
2133 case UI_GLINFO:
2134 UI_DrawGLInfo(&rect,scale, color, textStyle);
2135 break;
2136 case UI_KEYBINDSTATUS:
2137 UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
2138 break;
2139 default:
2140 break;
2141 }
2142
2143 }
2144
UI_OwnerDrawVisible(int flags)2145 static qboolean UI_OwnerDrawVisible(int flags) {
2146 qboolean vis = qtrue;
2147
2148 while (flags) {
2149
2150 if (flags & UI_SHOW_FFA) {
2151 if (trap_Cvar_VariableValue("g_gametype") != GT_FFA) {
2152 vis = qfalse;
2153 }
2154 flags &= ~UI_SHOW_FFA;
2155 }
2156
2157 if (flags & UI_SHOW_NOTFFA) {
2158 if (trap_Cvar_VariableValue("g_gametype") == GT_FFA) {
2159 vis = qfalse;
2160 }
2161 flags &= ~UI_SHOW_NOTFFA;
2162 }
2163
2164 if (flags & UI_SHOW_LEADER) {
2165 // these need to show when this client can give orders to a player or a group
2166 if (!uiInfo.teamLeader) {
2167 vis = qfalse;
2168 } else {
2169 // if showing yourself
2170 if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
2171 vis = qfalse;
2172 }
2173 }
2174 flags &= ~UI_SHOW_LEADER;
2175 }
2176 if (flags & UI_SHOW_NOTLEADER) {
2177 // these need to show when this client is assigning their own status or they are NOT the leader
2178 if (uiInfo.teamLeader) {
2179 // if not showing yourself
2180 if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
2181 vis = qfalse;
2182 }
2183 // these need to show when this client can give orders to a player or a group
2184 }
2185 flags &= ~UI_SHOW_NOTLEADER;
2186 }
2187 if (flags & UI_SHOW_FAVORITESERVERS) {
2188 // this assumes you only put this type of display flag on something showing in the proper context
2189 if (ui_netSource.integer != AS_FAVORITES) {
2190 vis = qfalse;
2191 }
2192 flags &= ~UI_SHOW_FAVORITESERVERS;
2193 }
2194 if (flags & UI_SHOW_NOTFAVORITESERVERS) {
2195 // this assumes you only put this type of display flag on something showing in the proper context
2196 if (ui_netSource.integer == AS_FAVORITES) {
2197 vis = qfalse;
2198 }
2199 flags &= ~UI_SHOW_NOTFAVORITESERVERS;
2200 }
2201 if (flags & UI_SHOW_ANYTEAMGAME) {
2202 if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM ) {
2203 vis = qfalse;
2204 }
2205 flags &= ~UI_SHOW_ANYTEAMGAME;
2206 }
2207 if (flags & UI_SHOW_ANYNONTEAMGAME) {
2208 if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM ) {
2209 vis = qfalse;
2210 }
2211 flags &= ~UI_SHOW_ANYNONTEAMGAME;
2212 }
2213 if (flags & UI_SHOW_NETANYTEAMGAME) {
2214 if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM ) {
2215 vis = qfalse;
2216 }
2217 flags &= ~UI_SHOW_NETANYTEAMGAME;
2218 }
2219 if (flags & UI_SHOW_NETANYNONTEAMGAME) {
2220 if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM ) {
2221 vis = qfalse;
2222 }
2223 flags &= ~UI_SHOW_NETANYNONTEAMGAME;
2224 }
2225 if (flags & UI_SHOW_NEWHIGHSCORE) {
2226 if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
2227 vis = qfalse;
2228 } else {
2229 if (uiInfo.soundHighScore) {
2230 if (trap_Cvar_VariableValue("sv_killserver") == 0) {
2231 // wait on server to go down before playing sound
2232 trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
2233 uiInfo.soundHighScore = qfalse;
2234 }
2235 }
2236 }
2237 flags &= ~UI_SHOW_NEWHIGHSCORE;
2238 }
2239 if (flags & UI_SHOW_NEWBESTTIME) {
2240 if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
2241 vis = qfalse;
2242 }
2243 flags &= ~UI_SHOW_NEWBESTTIME;
2244 }
2245 if (flags & UI_SHOW_DEMOAVAILABLE) {
2246 if (!uiInfo.demoAvailable) {
2247 vis = qfalse;
2248 }
2249 flags &= ~UI_SHOW_DEMOAVAILABLE;
2250 } else {
2251 flags = 0;
2252 }
2253 }
2254 return vis;
2255 }
2256
UI_Handicap_HandleKey(int flags,float * special,int key)2257 static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
2258 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2259 int h;
2260 h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
2261 if (key == K_MOUSE2) {
2262 h -= 5;
2263 } else {
2264 h += 5;
2265 }
2266 if (h > 100) {
2267 h = 5;
2268 } else if (h < 0) {
2269 h = 100;
2270 }
2271 trap_Cvar_Set( "handicap", va( "%i", h) );
2272 return qtrue;
2273 }
2274 return qfalse;
2275 }
2276
UI_Effects_HandleKey(int flags,float * special,int key)2277 static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
2278 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2279
2280 if (key == K_MOUSE2) {
2281 uiInfo.effectsColor--;
2282 } else {
2283 uiInfo.effectsColor++;
2284 }
2285
2286 if( uiInfo.effectsColor > 6 ) {
2287 uiInfo.effectsColor = 0;
2288 } else if (uiInfo.effectsColor < 0) {
2289 uiInfo.effectsColor = 6;
2290 }
2291
2292 trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
2293 return qtrue;
2294 }
2295 return qfalse;
2296 }
2297
UI_ClanName_HandleKey(int flags,float * special,int key)2298 static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
2299 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2300 int i;
2301 i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2302 if (uiInfo.teamList[i].cinematic >= 0) {
2303 trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
2304 uiInfo.teamList[i].cinematic = -1;
2305 }
2306 if (key == K_MOUSE2) {
2307 i--;
2308 } else {
2309 i++;
2310 }
2311 if (i >= uiInfo.teamCount) {
2312 i = 0;
2313 } else if (i < 0) {
2314 i = uiInfo.teamCount - 1;
2315 }
2316 trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
2317 UI_HeadCountByTeam();
2318 UI_FeederSelection(FEEDER_HEADS, 0);
2319 updateModel = qtrue;
2320 return qtrue;
2321 }
2322 return qfalse;
2323 }
2324
UI_GameType_HandleKey(int flags,float * special,int key,qboolean resetMap)2325 static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
2326 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2327 int oldCount = UI_MapCountByGameType(qtrue);
2328
2329 // hard coded mess here
2330 if (key == K_MOUSE2) {
2331 ui_gameType.integer--;
2332 if (ui_gameType.integer == 2) {
2333 ui_gameType.integer = 1;
2334 } else if (ui_gameType.integer < 2) {
2335 ui_gameType.integer = uiInfo.numGameTypes - 1;
2336 }
2337 } else {
2338 ui_gameType.integer++;
2339 if (ui_gameType.integer >= uiInfo.numGameTypes) {
2340 ui_gameType.integer = 1;
2341 } else if (ui_gameType.integer == 2) {
2342 ui_gameType.integer = 3;
2343 }
2344 }
2345
2346 if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
2347 trap_Cvar_Set("ui_Q3Model", "1");
2348 } else {
2349 trap_Cvar_Set("ui_Q3Model", "0");
2350 }
2351
2352 trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
2353 UI_SetCapFragLimits(qtrue);
2354 UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
2355 if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
2356 trap_Cvar_Set( "ui_currentMap", "0");
2357 Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
2358 }
2359 return qtrue;
2360 }
2361 return qfalse;
2362 }
2363
UI_NetGameType_HandleKey(int flags,float * special,int key)2364 static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
2365 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2366
2367 if (key == K_MOUSE2) {
2368 ui_netGameType.integer--;
2369 } else {
2370 ui_netGameType.integer++;
2371 }
2372
2373 if (ui_netGameType.integer < 0) {
2374 ui_netGameType.integer = uiInfo.numGameTypes - 1;
2375 } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
2376 ui_netGameType.integer = 0;
2377 }
2378
2379 trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
2380 trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
2381 trap_Cvar_Set( "ui_currentNetMap", "0");
2382 UI_MapCountByGameType(qfalse);
2383 Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
2384 return qtrue;
2385 }
2386 return qfalse;
2387 }
2388
UI_JoinGameType_HandleKey(int flags,float * special,int key)2389 static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
2390 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2391
2392 if (key == K_MOUSE2) {
2393 ui_joinGameType.integer--;
2394 } else {
2395 ui_joinGameType.integer++;
2396 }
2397
2398 if (ui_joinGameType.integer < 0) {
2399 ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
2400 } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
2401 ui_joinGameType.integer = 0;
2402 }
2403
2404 trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
2405 UI_BuildServerDisplayList(qtrue);
2406 return qtrue;
2407 }
2408 return qfalse;
2409 }
2410
2411
2412
UI_Skill_HandleKey(int flags,float * special,int key)2413 static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
2414 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2415 int i = trap_Cvar_VariableValue( "g_spSkill" );
2416
2417 if (key == K_MOUSE2) {
2418 i--;
2419 } else {
2420 i++;
2421 }
2422
2423 if (i < 1) {
2424 i = numSkillLevels;
2425 } else if (i > numSkillLevels) {
2426 i = 1;
2427 }
2428
2429 trap_Cvar_Set("g_spSkill", va("%i", i));
2430 return qtrue;
2431 }
2432 return qfalse;
2433 }
2434
UI_TeamName_HandleKey(int flags,float * special,int key,qboolean blue)2435 static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
2436 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2437 int i;
2438 i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
2439
2440 if (key == K_MOUSE2) {
2441 i--;
2442 } else {
2443 i++;
2444 }
2445
2446 if (i >= uiInfo.teamCount) {
2447 i = 0;
2448 } else if (i < 0) {
2449 i = uiInfo.teamCount - 1;
2450 }
2451
2452 trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
2453
2454 return qtrue;
2455 }
2456 return qfalse;
2457 }
2458
UI_TeamMember_HandleKey(int flags,float * special,int key,qboolean blue,int num)2459 static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
2460 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2461 // 0 - None
2462 // 1 - Human
2463 // 2..NumCharacters - Bot
2464 char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
2465 int value = trap_Cvar_VariableValue(cvar);
2466
2467 if (key == K_MOUSE2) {
2468 value--;
2469 } else {
2470 value++;
2471 }
2472
2473 if (ui_actualNetGameType.integer >= GT_TEAM) {
2474 if (value >= uiInfo.characterCount + 2) {
2475 value = 0;
2476 } else if (value < 0) {
2477 value = uiInfo.characterCount + 2 - 1;
2478 }
2479 } else {
2480 if (value >= UI_GetNumBots() + 2) {
2481 value = 0;
2482 } else if (value < 0) {
2483 value = UI_GetNumBots() + 2 - 1;
2484 }
2485 }
2486
2487 trap_Cvar_Set(cvar, va("%i", value));
2488 return qtrue;
2489 }
2490 return qfalse;
2491 }
2492
UI_NetSource_HandleKey(int flags,float * special,int key)2493 static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
2494 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2495
2496 if (key == K_MOUSE2) {
2497 ui_netSource.integer--;
2498 } else {
2499 ui_netSource.integer++;
2500 }
2501
2502 if (ui_netSource.integer >= numNetSources) {
2503 ui_netSource.integer = 0;
2504 } else if (ui_netSource.integer < 0) {
2505 ui_netSource.integer = numNetSources - 1;
2506 }
2507
2508 UI_BuildServerDisplayList(qtrue);
2509 if (ui_netSource.integer != AS_GLOBAL) {
2510 UI_StartServerRefresh(qtrue);
2511 }
2512 trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
2513 return qtrue;
2514 }
2515 return qfalse;
2516 }
2517
UI_NetFilter_HandleKey(int flags,float * special,int key)2518 static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
2519 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2520
2521 if (key == K_MOUSE2) {
2522 ui_serverFilterType.integer--;
2523 } else {
2524 ui_serverFilterType.integer++;
2525 }
2526
2527 if (ui_serverFilterType.integer >= numServerFilters) {
2528 ui_serverFilterType.integer = 0;
2529 } else if (ui_serverFilterType.integer < 0) {
2530 ui_serverFilterType.integer = numServerFilters - 1;
2531 }
2532 UI_BuildServerDisplayList(qtrue);
2533 return qtrue;
2534 }
2535 return qfalse;
2536 }
2537
UI_OpponentName_HandleKey(int flags,float * special,int key)2538 static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
2539 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2540 if (key == K_MOUSE2) {
2541 UI_PriorOpponent();
2542 } else {
2543 UI_NextOpponent();
2544 }
2545 return qtrue;
2546 }
2547 return qfalse;
2548 }
2549
UI_BotName_HandleKey(int flags,float * special,int key)2550 static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
2551 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2552 int game = trap_Cvar_VariableValue("g_gametype");
2553 int value = uiInfo.botIndex;
2554
2555 if (key == K_MOUSE2) {
2556 value--;
2557 } else {
2558 value++;
2559 }
2560
2561 if (game >= GT_TEAM) {
2562 if (value >= uiInfo.characterCount + 2) {
2563 value = 0;
2564 } else if (value < 0) {
2565 value = uiInfo.characterCount + 2 - 1;
2566 }
2567 } else {
2568 if (value >= UI_GetNumBots() + 2) {
2569 value = 0;
2570 } else if (value < 0) {
2571 value = UI_GetNumBots() + 2 - 1;
2572 }
2573 }
2574 uiInfo.botIndex = value;
2575 return qtrue;
2576 }
2577 return qfalse;
2578 }
2579
UI_BotSkill_HandleKey(int flags,float * special,int key)2580 static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
2581 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2582 if (key == K_MOUSE2) {
2583 uiInfo.skillIndex--;
2584 } else {
2585 uiInfo.skillIndex++;
2586 }
2587 if (uiInfo.skillIndex >= numSkillLevels) {
2588 uiInfo.skillIndex = 0;
2589 } else if (uiInfo.skillIndex < 0) {
2590 uiInfo.skillIndex = numSkillLevels-1;
2591 }
2592 return qtrue;
2593 }
2594 return qfalse;
2595 }
2596
UI_RedBlue_HandleKey(int flags,float * special,int key)2597 static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
2598 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2599 uiInfo.redBlue ^= 1;
2600 return qtrue;
2601 }
2602 return qfalse;
2603 }
2604
UI_Crosshair_HandleKey(int flags,float * special,int key)2605 static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
2606 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2607 if (key == K_MOUSE2) {
2608 uiInfo.currentCrosshair--;
2609 } else {
2610 uiInfo.currentCrosshair++;
2611 }
2612
2613 if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
2614 uiInfo.currentCrosshair = 0;
2615 } else if (uiInfo.currentCrosshair < 0) {
2616 uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
2617 }
2618 trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair));
2619 return qtrue;
2620 }
2621 return qfalse;
2622 }
2623
2624
2625
UI_SelectedPlayer_HandleKey(int flags,float * special,int key)2626 static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
2627 if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2628 int selected;
2629
2630 UI_BuildPlayerList();
2631 if (!uiInfo.teamLeader) {
2632 return qfalse;
2633 }
2634 selected = trap_Cvar_VariableValue("cg_selectedPlayer");
2635
2636 if (key == K_MOUSE2) {
2637 selected--;
2638 } else {
2639 selected++;
2640 }
2641
2642 if (selected > uiInfo.myTeamCount) {
2643 selected = 0;
2644 } else if (selected < 0) {
2645 selected = uiInfo.myTeamCount;
2646 }
2647
2648 if (selected == uiInfo.myTeamCount) {
2649 trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
2650 } else {
2651 trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
2652 }
2653 trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
2654 }
2655 return qfalse;
2656 }
2657
2658
UI_OwnerDrawHandleKey(int ownerDraw,int flags,float * special,int key)2659 static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
2660 switch (ownerDraw) {
2661 case UI_HANDICAP:
2662 return UI_Handicap_HandleKey(flags, special, key);
2663 break;
2664 case UI_EFFECTS:
2665 return UI_Effects_HandleKey(flags, special, key);
2666 break;
2667 case UI_CLANNAME:
2668 return UI_ClanName_HandleKey(flags, special, key);
2669 break;
2670 case UI_GAMETYPE:
2671 return UI_GameType_HandleKey(flags, special, key, qtrue);
2672 break;
2673 case UI_NETGAMETYPE:
2674 return UI_NetGameType_HandleKey(flags, special, key);
2675 break;
2676 case UI_JOINGAMETYPE:
2677 return UI_JoinGameType_HandleKey(flags, special, key);
2678 break;
2679 case UI_SKILL:
2680 return UI_Skill_HandleKey(flags, special, key);
2681 break;
2682 case UI_BLUETEAMNAME:
2683 return UI_TeamName_HandleKey(flags, special, key, qtrue);
2684 break;
2685 case UI_REDTEAMNAME:
2686 return UI_TeamName_HandleKey(flags, special, key, qfalse);
2687 break;
2688 case UI_BLUETEAM1:
2689 case UI_BLUETEAM2:
2690 case UI_BLUETEAM3:
2691 case UI_BLUETEAM4:
2692 case UI_BLUETEAM5:
2693 UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
2694 break;
2695 case UI_REDTEAM1:
2696 case UI_REDTEAM2:
2697 case UI_REDTEAM3:
2698 case UI_REDTEAM4:
2699 case UI_REDTEAM5:
2700 UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
2701 break;
2702 case UI_NETSOURCE:
2703 UI_NetSource_HandleKey(flags, special, key);
2704 break;
2705 case UI_NETFILTER:
2706 UI_NetFilter_HandleKey(flags, special, key);
2707 break;
2708 case UI_OPPONENT_NAME:
2709 UI_OpponentName_HandleKey(flags, special, key);
2710 break;
2711 case UI_BOTNAME:
2712 return UI_BotName_HandleKey(flags, special, key);
2713 break;
2714 case UI_BOTSKILL:
2715 return UI_BotSkill_HandleKey(flags, special, key);
2716 break;
2717 case UI_REDBLUE:
2718 UI_RedBlue_HandleKey(flags, special, key);
2719 break;
2720 case UI_CROSSHAIR:
2721 UI_Crosshair_HandleKey(flags, special, key);
2722 break;
2723 case UI_SELECTEDPLAYER:
2724 UI_SelectedPlayer_HandleKey(flags, special, key);
2725 break;
2726 default:
2727 break;
2728 }
2729
2730 return qfalse;
2731 }
2732
2733
UI_GetValue(int ownerDraw)2734 static float UI_GetValue(int ownerDraw) {
2735 return 0;
2736 }
2737
2738 /*
2739 =================
2740 UI_ServersQsortCompare
2741 =================
2742 */
UI_ServersQsortCompare(const void * arg1,const void * arg2)2743 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
2744 return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
2745 }
2746
2747
2748 /*
2749 =================
2750 UI_ServersSort
2751 =================
2752 */
UI_ServersSort(int column,qboolean force)2753 void UI_ServersSort(int column, qboolean force) {
2754
2755 if ( !force ) {
2756 if ( uiInfo.serverStatus.sortKey == column ) {
2757 return;
2758 }
2759 }
2760
2761 uiInfo.serverStatus.sortKey = column;
2762 qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
2763 }
2764
2765 /*
2766 static void UI_StartSinglePlayer(void) {
2767 int i,j, k, skill;
2768 char buff[1024];
2769 i = trap_Cvar_VariableValue( "ui_currentTier" );
2770 if (i < 0 || i >= tierCount) {
2771 i = 0;
2772 }
2773 j = trap_Cvar_VariableValue("ui_currentMap");
2774 if (j < 0 || j > MAPS_PER_TIER) {
2775 j = 0;
2776 }
2777
2778 trap_Cvar_SetValue( "singleplayer", 1 );
2779 trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 7, tierList[i].gameTypes[j] ) );
2780 trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
2781 skill = trap_Cvar_VariableValue( "g_spSkill" );
2782
2783 if (j == MAPS_PER_TIER-1) {
2784 k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2785 Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
2786 } else {
2787 k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2788 for (i = 0; i < PLAYERS_PER_TEAM; i++) {
2789 Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Blue", teamList[k].teamMembers[i]);
2790 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2791 }
2792
2793 k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2794 for (i = 1; i < PLAYERS_PER_TEAM; i++) {
2795 Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Red", teamList[k].teamMembers[i]);
2796 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2797 }
2798 trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
2799 }
2800
2801
2802 }
2803 */
2804
2805 /*
2806 ===============
2807 UI_LoadMods
2808 ===============
2809 */
UI_LoadMods(void)2810 static void UI_LoadMods( void ) {
2811 int numdirs;
2812 char dirlist[2048];
2813 char *dirptr;
2814 char *descptr;
2815 int i;
2816 int dirlen;
2817
2818 uiInfo.modCount = 0;
2819 numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
2820 dirptr = dirlist;
2821 for( i = 0; i < numdirs; i++ ) {
2822 dirlen = strlen( dirptr ) + 1;
2823 descptr = dirptr + dirlen;
2824 uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
2825 uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
2826 dirptr += dirlen + strlen(descptr) + 1;
2827 uiInfo.modCount++;
2828 if (uiInfo.modCount >= MAX_MODS) {
2829 break;
2830 }
2831 }
2832
2833 }
2834
2835
2836 /*
2837 ===============
2838 UI_LoadTeams
2839 ===============
2840 */
UI_LoadTeams(void)2841 static void UI_LoadTeams( void ) {
2842 char teamList[4096];
2843 char *teamName;
2844 int i, len, count;
2845
2846 count = trap_FS_GetFileList( "", "team", teamList, 4096 );
2847
2848 if (count) {
2849 teamName = teamList;
2850 for ( i = 0; i < count; i++ ) {
2851 len = strlen( teamName );
2852 UI_ParseTeamInfo(teamName);
2853 teamName += len + 1;
2854 }
2855 }
2856
2857 }
2858
2859
2860 /*
2861 ===============
2862 UI_LoadMovies
2863 ===============
2864 */
UI_LoadMovies(void)2865 static void UI_LoadMovies( void ) {
2866 char movielist[4096];
2867 char *moviename;
2868 int i, len;
2869
2870 uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
2871
2872 if (uiInfo.movieCount) {
2873 if (uiInfo.movieCount > MAX_MOVIES) {
2874 uiInfo.movieCount = MAX_MOVIES;
2875 }
2876 moviename = movielist;
2877 for ( i = 0; i < uiInfo.movieCount; i++ ) {
2878 len = strlen( moviename );
2879 if (!Q_stricmp(moviename + len - 4,".roq")) {
2880 moviename[len-4] = '\0';
2881 }
2882 Q_strupr(moviename);
2883 uiInfo.movieList[i] = String_Alloc(moviename);
2884 moviename += len + 1;
2885 }
2886 }
2887
2888 }
2889
2890
2891
2892 /*
2893 ===============
2894 UI_LoadDemos
2895 ===============
2896 */
UI_LoadDemos(void)2897 static void UI_LoadDemos( void ) {
2898 char demolist[4096];
2899 char demoExt[32];
2900 char *demoname;
2901 int i, len;
2902
2903 Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
2904
2905 uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
2906
2907 Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
2908
2909 if (uiInfo.demoCount) {
2910 if (uiInfo.demoCount > MAX_DEMOS) {
2911 uiInfo.demoCount = MAX_DEMOS;
2912 }
2913 demoname = demolist;
2914 for ( i = 0; i < uiInfo.demoCount; i++ ) {
2915 len = strlen( demoname );
2916 if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt)) {
2917 demoname[len-strlen(demoExt)] = '\0';
2918 }
2919 Q_strupr(demoname);
2920 uiInfo.demoList[i] = String_Alloc(demoname);
2921 demoname += len + 1;
2922 }
2923 }
2924
2925 }
2926
2927
UI_SetNextMap(int actual,int index)2928 static qboolean UI_SetNextMap(int actual, int index) {
2929 int i;
2930 for (i = actual + 1; i < uiInfo.mapCount; i++) {
2931 if (uiInfo.mapList[i].active) {
2932 Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
2933 return qtrue;
2934 }
2935 }
2936 return qfalse;
2937 }
2938
2939
UI_StartSkirmish(qboolean next)2940 static void UI_StartSkirmish(qboolean next) {
2941 int i, k, g, delay, temp;
2942 float skill;
2943 char buff[MAX_STRING_CHARS];
2944
2945 if (next) {
2946 int actual;
2947 int index = trap_Cvar_VariableValue("ui_mapIndex");
2948 UI_MapCountByGameType(qtrue);
2949 UI_SelectedMap(index, &actual);
2950 if (UI_SetNextMap(actual, index)) {
2951 } else {
2952 UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
2953 UI_MapCountByGameType(qtrue);
2954 Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
2955 }
2956 }
2957
2958 g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
2959 trap_Cvar_SetValue( "g_gametype", g );
2960 trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
2961 skill = trap_Cvar_VariableValue( "g_spSkill" );
2962 trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
2963
2964 k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2965
2966 trap_Cvar_Set("ui_singlePlayerActive", "1");
2967
2968 // set up sp overrides, will be replaced on postgame
2969 temp = trap_Cvar_VariableValue( "capturelimit" );
2970 trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
2971 temp = trap_Cvar_VariableValue( "fraglimit" );
2972 trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
2973
2974 UI_SetCapFragLimits(qfalse);
2975
2976 temp = trap_Cvar_VariableValue( "cg_drawTimer" );
2977 trap_Cvar_Set("ui_drawTimer", va("%i", temp));
2978 temp = trap_Cvar_VariableValue( "g_doWarmup" );
2979 trap_Cvar_Set("ui_doWarmup", va("%i", temp));
2980 temp = trap_Cvar_VariableValue( "g_friendlyFire" );
2981 trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
2982 temp = trap_Cvar_VariableValue( "sv_maxClients" );
2983 trap_Cvar_Set("ui_maxClients", va("%i", temp));
2984 temp = trap_Cvar_VariableValue( "g_warmup" );
2985 trap_Cvar_Set("ui_Warmup", va("%i", temp));
2986 temp = trap_Cvar_VariableValue( "sv_pure" );
2987 trap_Cvar_Set("ui_pure", va("%i", temp));
2988
2989 trap_Cvar_Set("cg_cameraOrbit", "0");
2990 trap_Cvar_Set("cg_thirdPerson", "0");
2991 trap_Cvar_Set("cg_drawTimer", "1");
2992 trap_Cvar_Set("g_doWarmup", "1");
2993 trap_Cvar_Set("g_warmup", "15");
2994 trap_Cvar_Set("sv_pure", "0");
2995 trap_Cvar_Set("g_friendlyFire", "0");
2996 trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
2997 trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
2998
2999 if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
3000 Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
3001 trap_Cvar_Set("ui_recordSPDemoName", buff);
3002 }
3003
3004 delay = 500;
3005
3006 if (g == GT_TOURNAMENT) {
3007 trap_Cvar_Set("sv_maxClients", "2");
3008 Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
3009 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3010 } else {
3011 temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
3012 trap_Cvar_Set("sv_maxClients", va("%d", temp));
3013 for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
3014 Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Blue", delay, uiInfo.teamList[k].teamMembers[i]);
3015 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3016 delay += 500;
3017 }
3018 k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
3019 for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
3020 Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Red", delay, uiInfo.teamList[k].teamMembers[i]);
3021 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3022 delay += 500;
3023 }
3024 }
3025 if (g >= GT_TEAM ) {
3026 trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
3027 }
3028 }
3029
UI_Update(const char * name)3030 static void UI_Update(const char *name) {
3031 int val = trap_Cvar_VariableValue(name);
3032
3033 if (Q_stricmp(name, "ui_SetName") == 0) {
3034 trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
3035 } else if (Q_stricmp(name, "ui_setRate") == 0) {
3036 float rate = trap_Cvar_VariableValue("rate");
3037 if (rate >= 5000) {
3038 trap_Cvar_Set("cl_maxpackets", "30");
3039 trap_Cvar_Set("cl_packetdup", "1");
3040 } else if (rate >= 4000) {
3041 trap_Cvar_Set("cl_maxpackets", "15");
3042 trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
3043 } else {
3044 trap_Cvar_Set("cl_maxpackets", "15");
3045 trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
3046 }
3047 } else if (Q_stricmp(name, "ui_GetName") == 0) {
3048 trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
3049 } else if (Q_stricmp(name, "r_colorbits") == 0) {
3050 switch (val) {
3051 case 0:
3052 trap_Cvar_SetValue( "r_depthbits", 0 );
3053 trap_Cvar_SetValue( "r_stencilbits", 0 );
3054 break;
3055 case 16:
3056 trap_Cvar_SetValue( "r_depthbits", 16 );
3057 trap_Cvar_SetValue( "r_stencilbits", 0 );
3058 break;
3059 case 32:
3060 trap_Cvar_SetValue( "r_depthbits", 24 );
3061 break;
3062 }
3063 } else if (Q_stricmp(name, "r_lodbias") == 0) {
3064 switch (val) {
3065 case 0:
3066 trap_Cvar_SetValue( "r_subdivisions", 4 );
3067 break;
3068 case 1:
3069 trap_Cvar_SetValue( "r_subdivisions", 12 );
3070 break;
3071 case 2:
3072 trap_Cvar_SetValue( "r_subdivisions", 20 );
3073 break;
3074 }
3075 } else if (Q_stricmp(name, "ui_glCustom") == 0) {
3076 switch (val) {
3077 case 0: // high quality
3078 trap_Cvar_SetValue( "r_fullScreen", 1 );
3079 trap_Cvar_SetValue( "r_subdivisions", 4 );
3080 trap_Cvar_SetValue( "r_vertexlight", 0 );
3081 trap_Cvar_SetValue( "r_lodbias", 0 );
3082 trap_Cvar_SetValue( "r_colorbits", 32 );
3083 trap_Cvar_SetValue( "r_depthbits", 24 );
3084 trap_Cvar_SetValue( "r_picmip", 0 );
3085 trap_Cvar_SetValue( "r_mode", 4 );
3086 trap_Cvar_SetValue( "r_texturebits", 32 );
3087 trap_Cvar_SetValue( "r_fastSky", 0 );
3088 trap_Cvar_SetValue( "r_inGameVideo", 1 );
3089 trap_Cvar_SetValue( "cg_shadows", 1 );
3090 trap_Cvar_SetValue( "cg_brassTime", 2500 );
3091 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
3092 break;
3093 case 1: // normal
3094 trap_Cvar_SetValue( "r_fullScreen", 1 );
3095 trap_Cvar_SetValue( "r_subdivisions", 12 );
3096 trap_Cvar_SetValue( "r_vertexlight", 0 );
3097 trap_Cvar_SetValue( "r_lodbias", 0 );
3098 trap_Cvar_SetValue( "r_colorbits", 0 );
3099 trap_Cvar_SetValue( "r_depthbits", 24 );
3100 trap_Cvar_SetValue( "r_picmip", 1 );
3101 trap_Cvar_SetValue( "r_mode", 3 );
3102 trap_Cvar_SetValue( "r_texturebits", 0 );
3103 trap_Cvar_SetValue( "r_fastSky", 0 );
3104 trap_Cvar_SetValue( "r_inGameVideo", 1 );
3105 trap_Cvar_SetValue( "cg_brassTime", 2500 );
3106 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
3107 trap_Cvar_SetValue( "cg_shadows", 0 );
3108 break;
3109 case 2: // fast
3110 trap_Cvar_SetValue( "r_fullScreen", 1 );
3111 trap_Cvar_SetValue( "r_subdivisions", 8 );
3112 trap_Cvar_SetValue( "r_vertexlight", 0 );
3113 trap_Cvar_SetValue( "r_lodbias", 1 );
3114 trap_Cvar_SetValue( "r_colorbits", 0 );
3115 trap_Cvar_SetValue( "r_depthbits", 0 );
3116 trap_Cvar_SetValue( "r_picmip", 1 );
3117 trap_Cvar_SetValue( "r_mode", 3 );
3118 trap_Cvar_SetValue( "r_texturebits", 0 );
3119 trap_Cvar_SetValue( "cg_shadows", 0 );
3120 trap_Cvar_SetValue( "r_fastSky", 1 );
3121 trap_Cvar_SetValue( "r_inGameVideo", 0 );
3122 trap_Cvar_SetValue( "cg_brassTime", 0 );
3123 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
3124 break;
3125 case 3: // fastest
3126 trap_Cvar_SetValue( "r_fullScreen", 1 );
3127 trap_Cvar_SetValue( "r_subdivisions", 20 );
3128 trap_Cvar_SetValue( "r_vertexlight", 1 );
3129 trap_Cvar_SetValue( "r_lodbias", 2 );
3130 trap_Cvar_SetValue( "r_colorbits", 16 );
3131 trap_Cvar_SetValue( "r_depthbits", 16 );
3132 trap_Cvar_SetValue( "r_mode", 3 );
3133 trap_Cvar_SetValue( "r_picmip", 2 );
3134 trap_Cvar_SetValue( "r_texturebits", 16 );
3135 trap_Cvar_SetValue( "cg_shadows", 0 );
3136 trap_Cvar_SetValue( "cg_brassTime", 0 );
3137 trap_Cvar_SetValue( "r_fastSky", 1 );
3138 trap_Cvar_SetValue( "r_inGameVideo", 0 );
3139 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
3140 break;
3141 }
3142 } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
3143 if (val == 0) {
3144 trap_Cvar_SetValue( "m_pitch", 0.022f );
3145 } else {
3146 trap_Cvar_SetValue( "m_pitch", -0.022f );
3147 }
3148 }
3149 }
3150
UI_RunMenuScript(char ** args)3151 static void UI_RunMenuScript(char **args) {
3152 const char *name, *name2;
3153 char buff[1024];
3154
3155 if (String_Parse(args, &name)) {
3156 if (Q_stricmp(name, "StartServer") == 0) {
3157 int i, clients, oldclients;
3158 float skill;
3159 trap_Cvar_Set("cg_thirdPerson", "0");
3160 trap_Cvar_Set("cg_cameraOrbit", "0");
3161 trap_Cvar_Set("ui_singlePlayerActive", "0");
3162 trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
3163 trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
3164 trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
3165 trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
3166 trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
3167 skill = trap_Cvar_VariableValue( "g_spSkill" );
3168 // set max clients based on spots
3169 oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
3170 clients = 0;
3171 for (i = 0; i < PLAYERS_PER_TEAM; i++) {
3172 int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
3173 if (bot >= 0) {
3174 clients++;
3175 }
3176 bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
3177 if (bot >= 0) {
3178 clients++;
3179 }
3180 }
3181 if (clients == 0) {
3182 clients = 8;
3183 }
3184
3185 if (oldclients > clients) {
3186 clients = oldclients;
3187 }
3188
3189 trap_Cvar_Set("sv_maxClients", va("%d",clients));
3190
3191 for (i = 0; i < PLAYERS_PER_TEAM; i++) {
3192 int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
3193 if (bot > 1) {
3194 if (ui_actualNetGameType.integer >= GT_TEAM) {
3195 Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
3196 } else {
3197 Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
3198 }
3199 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3200 }
3201 bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
3202 if (bot > 1) {
3203 if (ui_actualNetGameType.integer >= GT_TEAM) {
3204 Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
3205 } else {
3206 Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
3207 }
3208 trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3209 }
3210 }
3211 } else if (Q_stricmp(name, "updateSPMenu") == 0) {
3212 UI_SetCapFragLimits(qtrue);
3213 UI_MapCountByGameType(qtrue);
3214 ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
3215 trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
3216 Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
3217 UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
3218 UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
3219 } else if (Q_stricmp(name, "resetDefaults") == 0) {
3220 trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
3221 trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
3222 Controls_SetDefaults();
3223 trap_Cvar_Set("com_introPlayed", "1" );
3224 trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
3225 } else if (Q_stricmp(name, "getCDKey") == 0) {
3226 char out[17];
3227 trap_GetCDKey(buff, 17);
3228 trap_Cvar_Set("cdkey1", "");
3229 trap_Cvar_Set("cdkey2", "");
3230 trap_Cvar_Set("cdkey3", "");
3231 trap_Cvar_Set("cdkey4", "");
3232 if (strlen(buff) == CDKEY_LEN) {
3233 Q_strncpyz(out, buff, 5);
3234 trap_Cvar_Set("cdkey1", out);
3235 Q_strncpyz(out, buff + 4, 5);
3236 trap_Cvar_Set("cdkey2", out);
3237 Q_strncpyz(out, buff + 8, 5);
3238 trap_Cvar_Set("cdkey3", out);
3239 Q_strncpyz(out, buff + 12, 5);
3240 trap_Cvar_Set("cdkey4", out);
3241 }
3242
3243 } else if (Q_stricmp(name, "verifyCDKey") == 0) {
3244 buff[0] = '\0';
3245 Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
3246 Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
3247 Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
3248 Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
3249 trap_Cvar_Set("cdkey", buff);
3250 if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
3251 trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
3252 trap_SetCDKey(buff);
3253 } else {
3254 trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
3255 }
3256 } else if (Q_stricmp(name, "loadArenas") == 0) {
3257 UI_LoadArenas();
3258 UI_MapCountByGameType(qfalse);
3259 Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
3260 } else if (Q_stricmp(name, "saveControls") == 0) {
3261 Controls_SetConfig(qtrue);
3262 } else if (Q_stricmp(name, "loadControls") == 0) {
3263 Controls_GetConfig();
3264 } else if (Q_stricmp(name, "clearError") == 0) {
3265 trap_Cvar_Set("com_errorMessage", "");
3266 } else if (Q_stricmp(name, "loadGameInfo") == 0) {
3267 #ifdef PRE_RELEASE_TADEMO
3268 UI_ParseGameInfo("demogameinfo.txt");
3269 #else
3270 UI_ParseGameInfo("gameinfo.txt");
3271 #endif
3272 UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
3273 } else if (Q_stricmp(name, "resetScores") == 0) {
3274 UI_ClearScores();
3275 } else if (Q_stricmp(name, "RefreshServers") == 0) {
3276 UI_StartServerRefresh(qtrue);
3277 UI_BuildServerDisplayList(qtrue);
3278 } else if (Q_stricmp(name, "RefreshFilter") == 0) {
3279 UI_StartServerRefresh(qfalse);
3280 UI_BuildServerDisplayList(qtrue);
3281 } else if (Q_stricmp(name, "RunSPDemo") == 0) {
3282 if (uiInfo.demoAvailable) {
3283 trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
3284 }
3285 } else if (Q_stricmp(name, "LoadDemos") == 0) {
3286 UI_LoadDemos();
3287 } else if (Q_stricmp(name, "LoadMovies") == 0) {
3288 UI_LoadMovies();
3289 } else if (Q_stricmp(name, "LoadMods") == 0) {
3290 UI_LoadMods();
3291 } else if (Q_stricmp(name, "playMovie") == 0) {
3292 if (uiInfo.previewMovie >= 0) {
3293 trap_CIN_StopCinematic(uiInfo.previewMovie);
3294 }
3295 trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
3296 } else if (Q_stricmp(name, "RunMod") == 0) {
3297 trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
3298 trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
3299 } else if (Q_stricmp(name, "RunDemo") == 0) {
3300 trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
3301 } else if (Q_stricmp(name, "Quake3") == 0) {
3302 trap_Cvar_Set( "fs_game", "");
3303 trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
3304 } else if (Q_stricmp(name, "closeJoin") == 0) {
3305 if (uiInfo.serverStatus.refreshActive) {
3306 UI_StopServerRefresh();
3307 uiInfo.serverStatus.nextDisplayRefresh = 0;
3308 uiInfo.nextServerStatusRefresh = 0;
3309 uiInfo.nextFindPlayerRefresh = 0;
3310 UI_BuildServerDisplayList(qtrue);
3311 } else {
3312 Menus_CloseByName("joinserver");
3313 Menus_OpenByName("main");
3314 }
3315 } else if (Q_stricmp(name, "StopRefresh") == 0) {
3316 UI_StopServerRefresh();
3317 uiInfo.serverStatus.nextDisplayRefresh = 0;
3318 uiInfo.nextServerStatusRefresh = 0;
3319 uiInfo.nextFindPlayerRefresh = 0;
3320 } else if (Q_stricmp(name, "UpdateFilter") == 0) {
3321 if (ui_netSource.integer == AS_LOCAL) {
3322 UI_StartServerRefresh(qtrue);
3323 }
3324 UI_BuildServerDisplayList(qtrue);
3325 UI_FeederSelection(FEEDER_SERVERS, 0);
3326 } else if (Q_stricmp(name, "ServerStatus") == 0) {
3327 trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
3328 UI_BuildServerStatus(qtrue);
3329 } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
3330 Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
3331 UI_BuildServerStatus(qtrue);
3332 Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
3333 } else if (Q_stricmp(name, "FindPlayer") == 0) {
3334 UI_BuildFindPlayerList(qtrue);
3335 // clear the displayed server status info
3336 uiInfo.serverStatusInfo.numLines = 0;
3337 Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
3338 } else if (Q_stricmp(name, "JoinServer") == 0) {
3339 trap_Cvar_Set("cg_thirdPerson", "0");
3340 trap_Cvar_Set("cg_cameraOrbit", "0");
3341 trap_Cvar_Set("ui_singlePlayerActive", "0");
3342 if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
3343 trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
3344 trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
3345 }
3346 } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
3347 trap_Cvar_Set("ui_singlePlayerActive", "0");
3348 if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
3349 trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
3350 }
3351 } else if (Q_stricmp(name, "Quit") == 0) {
3352 trap_Cvar_Set("ui_singlePlayerActive", "0");
3353 trap_Cmd_ExecuteText( EXEC_NOW, "quit");
3354 } else if (Q_stricmp(name, "Controls") == 0) {
3355 trap_Cvar_Set( "cl_paused", "1" );
3356 trap_Key_SetCatcher( KEYCATCH_UI );
3357 Menus_CloseAll();
3358 Menus_ActivateByName("setup_menu2");
3359 } else if (Q_stricmp(name, "Leave") == 0) {
3360 trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
3361 trap_Key_SetCatcher( KEYCATCH_UI );
3362 Menus_CloseAll();
3363 Menus_ActivateByName("main");
3364 } else if (Q_stricmp(name, "ServerSort") == 0) {
3365 int sortColumn;
3366 if (Int_Parse(args, &sortColumn)) {
3367 // if same column we're already sorting on then flip the direction
3368 if (sortColumn == uiInfo.serverStatus.sortKey) {
3369 uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
3370 }
3371 // make sure we sort again
3372 UI_ServersSort(sortColumn, qtrue);
3373 }
3374 } else if (Q_stricmp(name, "nextSkirmish") == 0) {
3375 UI_StartSkirmish(qtrue);
3376 } else if (Q_stricmp(name, "SkirmishStart") == 0) {
3377 UI_StartSkirmish(qfalse);
3378 } else if (Q_stricmp(name, "closeingame") == 0) {
3379 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3380 trap_Key_ClearStates();
3381 trap_Cvar_Set( "cl_paused", "0" );
3382 Menus_CloseAll();
3383 } else if (Q_stricmp(name, "voteMap") == 0) {
3384 if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
3385 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
3386 }
3387 } else if (Q_stricmp(name, "voteKick") == 0) {
3388 if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
3389 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
3390 }
3391 } else if (Q_stricmp(name, "voteGame") == 0) {
3392 if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
3393 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
3394 }
3395 } else if (Q_stricmp(name, "voteLeader") == 0) {
3396 if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
3397 trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
3398 }
3399 } else if (Q_stricmp(name, "addBot") == 0) {
3400 if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) {
3401 trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
3402 } else {
3403 trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
3404 }
3405 } else if (Q_stricmp(name, "addFavorite") == 0) {
3406 if (ui_netSource.integer != AS_FAVORITES) {
3407 char name[MAX_NAME_LENGTH];
3408 char addr[MAX_NAME_LENGTH];
3409 int res;
3410
3411 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
3412 name[0] = addr[0] = '\0';
3413 Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
3414 Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
3415 if (strlen(name) > 0 && strlen(addr) > 0) {
3416 res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
3417 if (res == 0) {
3418 // server already in the list
3419 Com_Printf("Favorite already in list\n");
3420 }
3421 else if (res == -1) {
3422 // list full
3423 Com_Printf("Favorite list full\n");
3424 }
3425 else {
3426 // successfully added
3427 Com_Printf("Added favorite server %s\n", addr);
3428 }
3429 }
3430 }
3431 } else if (Q_stricmp(name, "deleteFavorite") == 0) {
3432 if (ui_netSource.integer == AS_FAVORITES) {
3433 char addr[MAX_NAME_LENGTH];
3434 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
3435 addr[0] = '\0';
3436 Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
3437 if (strlen(addr) > 0) {
3438 trap_LAN_RemoveServer(AS_FAVORITES, addr);
3439 }
3440 }
3441 } else if (Q_stricmp(name, "createFavorite") == 0) {
3442 if (ui_netSource.integer == AS_FAVORITES) {
3443 char name[MAX_NAME_LENGTH];
3444 char addr[MAX_NAME_LENGTH];
3445 int res;
3446
3447 name[0] = addr[0] = '\0';
3448 Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
3449 Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
3450 if (strlen(name) > 0 && strlen(addr) > 0) {
3451 res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
3452 if (res == 0) {
3453 // server already in the list
3454 Com_Printf("Favorite already in list\n");
3455 }
3456 else if (res == -1) {
3457 // list full
3458 Com_Printf("Favorite list full\n");
3459 }
3460 else {
3461 // successfully added
3462 Com_Printf("Added favorite server %s\n", addr);
3463 }
3464 }
3465 }
3466 } else if (Q_stricmp(name, "orders") == 0) {
3467 const char *orders;
3468 if (String_Parse(args, &orders)) {
3469 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3470 if (selectedPlayer < uiInfo.myTeamCount) {
3471 strcpy(buff, orders);
3472 trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
3473 trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3474 } else {
3475 int i;
3476 for (i = 0; i < uiInfo.myTeamCount; i++) {
3477 if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
3478 continue;
3479 }
3480 strcpy(buff, orders);
3481 trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
3482 trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3483 }
3484 }
3485 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3486 trap_Key_ClearStates();
3487 trap_Cvar_Set( "cl_paused", "0" );
3488 Menus_CloseAll();
3489 }
3490 } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
3491 const char *orders;
3492 if (String_Parse(args, &orders)) {
3493 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3494 if (selectedPlayer == uiInfo.myTeamCount) {
3495 trap_Cmd_ExecuteText( EXEC_APPEND, orders );
3496 trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3497 }
3498 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3499 trap_Key_ClearStates();
3500 trap_Cvar_Set( "cl_paused", "0" );
3501 Menus_CloseAll();
3502 }
3503 } else if (Q_stricmp(name, "voiceOrders") == 0) {
3504 const char *orders;
3505 if (String_Parse(args, &orders)) {
3506 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3507 if (selectedPlayer < uiInfo.myTeamCount) {
3508 strcpy(buff, orders);
3509 trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
3510 trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3511 }
3512 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3513 trap_Key_ClearStates();
3514 trap_Cvar_Set( "cl_paused", "0" );
3515 Menus_CloseAll();
3516 }
3517 } else if (Q_stricmp(name, "glCustom") == 0) {
3518 trap_Cvar_Set("ui_glCustom", "4");
3519 } else if (Q_stricmp(name, "update") == 0) {
3520 if (String_Parse(args, &name2)) {
3521 UI_Update(name2);
3522 }
3523 } else if (Q_stricmp(name, "setPbClStatus") == 0) {
3524 int stat;
3525 if ( Int_Parse( args, &stat ) )
3526 trap_SetPbClStatus( stat );
3527 }
3528 else {
3529 Com_Printf("unknown UI script %s\n", name);
3530 }
3531 }
3532 }
3533
UI_GetTeamColor(vec4_t * color)3534 static void UI_GetTeamColor(vec4_t *color) {
3535 }
3536
3537 /*
3538 ==================
3539 UI_MapCountByGameType
3540 ==================
3541 */
UI_MapCountByGameType(qboolean singlePlayer)3542 static int UI_MapCountByGameType(qboolean singlePlayer) {
3543 int i, c, game;
3544 c = 0;
3545 game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
3546 if (game == GT_SINGLE_PLAYER) {
3547 game++;
3548 }
3549 if (game == GT_TEAM) {
3550 game = GT_FFA;
3551 }
3552
3553 for (i = 0; i < uiInfo.mapCount; i++) {
3554 uiInfo.mapList[i].active = qfalse;
3555 if ( uiInfo.mapList[i].typeBits & (1 << game)) {
3556 if (singlePlayer) {
3557 if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
3558 continue;
3559 }
3560 }
3561 c++;
3562 uiInfo.mapList[i].active = qtrue;
3563 }
3564 }
3565 return c;
3566 }
3567
UI_hasSkinForBase(const char * base,const char * team)3568 qboolean UI_hasSkinForBase(const char *base, const char *team) {
3569 char test[1024];
3570
3571 Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
3572
3573 if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
3574 return qtrue;
3575 }
3576 Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
3577
3578 if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
3579 return qtrue;
3580 }
3581 return qfalse;
3582 }
3583
3584 /*
3585 ==================
3586 UI_MapCountByTeam
3587 ==================
3588 */
UI_HeadCountByTeam(void)3589 static int UI_HeadCountByTeam(void) {
3590 static int init = 0;
3591 int i, j, k, c, tIndex;
3592
3593 c = 0;
3594 if (!init) {
3595 for (i = 0; i < uiInfo.characterCount; i++) {
3596 uiInfo.characterList[i].reference = 0;
3597 for (j = 0; j < uiInfo.teamCount; j++) {
3598 if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
3599 uiInfo.characterList[i].reference |= (1<<j);
3600 }
3601 }
3602 }
3603 init = 1;
3604 }
3605
3606 tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
3607
3608 // do names
3609 for (i = 0; i < uiInfo.characterCount; i++) {
3610 uiInfo.characterList[i].active = qfalse;
3611 for(j = 0; j < TEAM_MEMBERS; j++) {
3612 if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
3613 if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
3614 uiInfo.characterList[i].active = qtrue;
3615 c++;
3616 break;
3617 }
3618 }
3619 }
3620 }
3621
3622 // and then aliases
3623 for(j = 0; j < TEAM_MEMBERS; j++) {
3624 for(k = 0; k < uiInfo.aliasCount; k++) {
3625 if (uiInfo.aliasList[k].name != NULL) {
3626 if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
3627 for (i = 0; i < uiInfo.characterCount; i++) {
3628 if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
3629 if (uiInfo.characterList[i].active == qfalse) {
3630 uiInfo.characterList[i].active = qtrue;
3631 c++;
3632 }
3633 break;
3634 }
3635 }
3636 }
3637 }
3638 }
3639 }
3640 return c;
3641 }
3642
3643 /*
3644 ==================
3645 UI_InsertServerIntoDisplayList
3646 ==================
3647 */
UI_InsertServerIntoDisplayList(int num,int position)3648 static void UI_InsertServerIntoDisplayList(int num, int position) {
3649 int i;
3650
3651 if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
3652 return;
3653 }
3654 //
3655 uiInfo.serverStatus.numDisplayServers++;
3656 for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
3657 uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
3658 }
3659 uiInfo.serverStatus.displayServers[position] = num;
3660 }
3661
3662 /*
3663 ==================
3664 UI_RemoveServerFromDisplayList
3665 ==================
3666 */
UI_RemoveServerFromDisplayList(int num)3667 static void UI_RemoveServerFromDisplayList(int num) {
3668 int i, j;
3669
3670 for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
3671 if (uiInfo.serverStatus.displayServers[i] == num) {
3672 uiInfo.serverStatus.numDisplayServers--;
3673 for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
3674 uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
3675 }
3676 return;
3677 }
3678 }
3679 }
3680
3681 /*
3682 ==================
3683 UI_BinaryServerInsertion
3684 ==================
3685 */
UI_BinaryServerInsertion(int num)3686 static void UI_BinaryServerInsertion(int num) {
3687 int mid, offset, res, len;
3688
3689 // use binary search to insert server
3690 len = uiInfo.serverStatus.numDisplayServers;
3691 mid = len;
3692 offset = 0;
3693 res = 0;
3694 while(mid > 0) {
3695 mid = len >> 1;
3696 //
3697 res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
3698 uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
3699 // if equal
3700 if (res == 0) {
3701 UI_InsertServerIntoDisplayList(num, offset+mid);
3702 return;
3703 }
3704 // if larger
3705 else if (res == 1) {
3706 offset += mid;
3707 len -= mid;
3708 }
3709 // if smaller
3710 else {
3711 len -= mid;
3712 }
3713 }
3714 if (res == 1) {
3715 offset++;
3716 }
3717 UI_InsertServerIntoDisplayList(num, offset);
3718 }
3719
3720 /*
3721 ==================
3722 UI_BuildServerDisplayList
3723 ==================
3724 */
UI_BuildServerDisplayList(qboolean force)3725 static void UI_BuildServerDisplayList(qboolean force) {
3726 int i, count, clients, maxClients, ping, game, len, visible;
3727 char info[MAX_STRING_CHARS];
3728 // qboolean startRefresh = qtrue; TTimo: unused
3729 static int numinvisible;
3730
3731 if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
3732 return;
3733 }
3734 // if we shouldn't reset
3735 if ( force == 2 ) {
3736 force = 0;
3737 }
3738
3739 // do motd updates here too
3740 trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
3741 len = strlen(uiInfo.serverStatus.motd);
3742 if (len == 0) {
3743 strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
3744 len = strlen(uiInfo.serverStatus.motd);
3745 }
3746 if (len != uiInfo.serverStatus.motdLen) {
3747 uiInfo.serverStatus.motdLen = len;
3748 uiInfo.serverStatus.motdWidth = -1;
3749 }
3750
3751 if (force) {
3752 numinvisible = 0;
3753 // clear number of displayed servers
3754 uiInfo.serverStatus.numDisplayServers = 0;
3755 uiInfo.serverStatus.numPlayersOnServers = 0;
3756 // set list box index to zero
3757 Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
3758 // mark all servers as visible so we store ping updates for them
3759 trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
3760 }
3761
3762 // get the server count (comes from the master)
3763 count = trap_LAN_GetServerCount(ui_netSource.integer);
3764 if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
3765 // still waiting on a response from the master
3766 uiInfo.serverStatus.numDisplayServers = 0;
3767 uiInfo.serverStatus.numPlayersOnServers = 0;
3768 uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
3769 return;
3770 }
3771
3772 visible = qfalse;
3773 for (i = 0; i < count; i++) {
3774 // if we already got info for this server
3775 if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
3776 continue;
3777 }
3778 visible = qtrue;
3779 // get the ping for this server
3780 ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
3781 if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
3782
3783 trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
3784
3785 clients = atoi(Info_ValueForKey(info, "clients"));
3786 uiInfo.serverStatus.numPlayersOnServers += clients;
3787
3788 if (ui_browserShowEmpty.integer == 0) {
3789 if (clients == 0) {
3790 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3791 continue;
3792 }
3793 }
3794
3795 if (ui_browserShowFull.integer == 0) {
3796 maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
3797 if (clients == maxClients) {
3798 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3799 continue;
3800 }
3801 }
3802
3803 if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
3804 game = atoi(Info_ValueForKey(info, "gametype"));
3805 if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
3806 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3807 continue;
3808 }
3809 }
3810
3811 if (ui_serverFilterType.integer > 0) {
3812 if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
3813 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3814 continue;
3815 }
3816 }
3817 // make sure we never add a favorite server twice
3818 if (ui_netSource.integer == AS_FAVORITES) {
3819 UI_RemoveServerFromDisplayList(i);
3820 }
3821 // insert the server into the list
3822 UI_BinaryServerInsertion(i);
3823 // done with this server
3824 if (ping > 0) {
3825 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3826 numinvisible++;
3827 }
3828 }
3829 }
3830
3831 uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
3832
3833 // if there were no servers visible for ping updates
3834 if (!visible) {
3835 // UI_StopServerRefresh();
3836 // uiInfo.serverStatus.nextDisplayRefresh = 0;
3837 }
3838 }
3839
3840 typedef struct
3841 {
3842 char *name, *altName;
3843 } serverStatusCvar_t;
3844
3845 serverStatusCvar_t serverStatusCvars[] = {
3846 {"sv_hostname", "Name"},
3847 {"Address", ""},
3848 {"gamename", "Game name"},
3849 {"g_gametype", "Game type"},
3850 {"mapname", "Map"},
3851 {"version", ""},
3852 {"protocol", ""},
3853 {"timelimit", ""},
3854 {"fraglimit", ""},
3855 {NULL, NULL}
3856 };
3857
3858 /*
3859 ==================
3860 UI_SortServerStatusInfo
3861 ==================
3862 */
UI_SortServerStatusInfo(serverStatusInfo_t * info)3863 static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
3864 int i, j, index;
3865 char *tmp1, *tmp2;
3866
3867 // FIXME: if "gamename" == "baseq3" or "missionpack" then
3868 // replace the gametype number by FFA, CTF etc.
3869 //
3870 index = 0;
3871 for (i = 0; serverStatusCvars[i].name; i++) {
3872 for (j = 0; j < info->numLines; j++) {
3873 if ( !info->lines[j][1] || info->lines[j][1][0] ) {
3874 continue;
3875 }
3876 if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
3877 // swap lines
3878 tmp1 = info->lines[index][0];
3879 tmp2 = info->lines[index][3];
3880 info->lines[index][0] = info->lines[j][0];
3881 info->lines[index][3] = info->lines[j][3];
3882 info->lines[j][0] = tmp1;
3883 info->lines[j][3] = tmp2;
3884 //
3885 if ( strlen(serverStatusCvars[i].altName) ) {
3886 info->lines[index][0] = serverStatusCvars[i].altName;
3887 }
3888 index++;
3889 }
3890 }
3891 }
3892 }
3893
3894 /*
3895 ==================
3896 UI_GetServerStatusInfo
3897 ==================
3898 */
UI_GetServerStatusInfo(const char * serverAddress,serverStatusInfo_t * info)3899 static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
3900 char *p, *score, *ping, *name;
3901 int i, len;
3902
3903 if (!info) {
3904 trap_LAN_ServerStatus( serverAddress, NULL, 0);
3905 return qfalse;
3906 }
3907 memset(info, 0, sizeof(*info));
3908 if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
3909 Q_strncpyz(info->address, serverAddress, sizeof(info->address));
3910 p = info->text;
3911 info->numLines = 0;
3912 info->lines[info->numLines][0] = "Address";
3913 info->lines[info->numLines][1] = "";
3914 info->lines[info->numLines][2] = "";
3915 info->lines[info->numLines][3] = info->address;
3916 info->numLines++;
3917 // get the cvars
3918 while (p && *p) {
3919 p = strchr(p, '\\');
3920 if (!p) break;
3921 *p++ = '\0';
3922 if (*p == '\\')
3923 break;
3924 info->lines[info->numLines][0] = p;
3925 info->lines[info->numLines][1] = "";
3926 info->lines[info->numLines][2] = "";
3927 p = strchr(p, '\\');
3928 if (!p) break;
3929 *p++ = '\0';
3930 info->lines[info->numLines][3] = p;
3931
3932 info->numLines++;
3933 if (info->numLines >= MAX_SERVERSTATUS_LINES)
3934 break;
3935 }
3936 // get the player list
3937 if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
3938 // empty line
3939 info->lines[info->numLines][0] = "";
3940 info->lines[info->numLines][1] = "";
3941 info->lines[info->numLines][2] = "";
3942 info->lines[info->numLines][3] = "";
3943 info->numLines++;
3944 // header
3945 info->lines[info->numLines][0] = "num";
3946 info->lines[info->numLines][1] = "score";
3947 info->lines[info->numLines][2] = "ping";
3948 info->lines[info->numLines][3] = "name";
3949 info->numLines++;
3950 // parse players
3951 i = 0;
3952 len = 0;
3953 while (p && *p) {
3954 if (*p == '\\')
3955 *p++ = '\0';
3956 if (!p)
3957 break;
3958 score = p;
3959 p = strchr(p, ' ');
3960 if (!p)
3961 break;
3962 *p++ = '\0';
3963 ping = p;
3964 p = strchr(p, ' ');
3965 if (!p)
3966 break;
3967 *p++ = '\0';
3968 name = p;
3969 Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
3970 info->lines[info->numLines][0] = &info->pings[len];
3971 len += strlen(&info->pings[len]) + 1;
3972 info->lines[info->numLines][1] = score;
3973 info->lines[info->numLines][2] = ping;
3974 info->lines[info->numLines][3] = name;
3975 info->numLines++;
3976 if (info->numLines >= MAX_SERVERSTATUS_LINES)
3977 break;
3978 p = strchr(p, '\\');
3979 if (!p)
3980 break;
3981 *p++ = '\0';
3982 //
3983 i++;
3984 }
3985 }
3986 UI_SortServerStatusInfo( info );
3987 return qtrue;
3988 }
3989 return qfalse;
3990 }
3991
3992 /*
3993 ==================
3994 stristr
3995 ==================
3996 */
stristr(char * str,char * charset)3997 static char *stristr(char *str, char *charset) {
3998 int i;
3999
4000 while(*str) {
4001 for (i = 0; charset[i] && str[i]; i++) {
4002 if (toupper(charset[i]) != toupper(str[i])) break;
4003 }
4004 if (!charset[i]) return str;
4005 str++;
4006 }
4007 return NULL;
4008 }
4009
4010 /*
4011 ==================
4012 UI_BuildFindPlayerList
4013 ==================
4014 */
UI_BuildFindPlayerList(qboolean force)4015 static void UI_BuildFindPlayerList(qboolean force) {
4016 static int numFound, numTimeOuts;
4017 int i, j, resend;
4018 serverStatusInfo_t info;
4019 char name[MAX_NAME_LENGTH+2];
4020 char infoString[MAX_STRING_CHARS];
4021
4022 if (!force) {
4023 if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
4024 return;
4025 }
4026 }
4027 else {
4028 memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
4029 uiInfo.numFoundPlayerServers = 0;
4030 uiInfo.currentFoundPlayerServer = 0;
4031 trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
4032 Q_CleanStr(uiInfo.findPlayerName);
4033 // should have a string of some length
4034 if (!strlen(uiInfo.findPlayerName)) {
4035 uiInfo.nextFindPlayerRefresh = 0;
4036 return;
4037 }
4038 // set resend time
4039 resend = ui_serverStatusTimeOut.integer / 2 - 10;
4040 if (resend < 50) {
4041 resend = 50;
4042 }
4043 trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
4044 // reset all server status requests
4045 trap_LAN_ServerStatus( NULL, NULL, 0);
4046 //
4047 uiInfo.numFoundPlayerServers = 1;
4048 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4049 sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4050 "searching %d...", uiInfo.pendingServerStatus.num);
4051 numFound = 0;
4052 numTimeOuts++;
4053 }
4054 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
4055 // if this pending server is valid
4056 if (uiInfo.pendingServerStatus.server[i].valid) {
4057 // try to get the server status for this server
4058 if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
4059 //
4060 numFound++;
4061 // parse through the server status lines
4062 for (j = 0; j < info.numLines; j++) {
4063 // should have ping info
4064 if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
4065 continue;
4066 }
4067 // clean string first
4068 Q_strncpyz(name, info.lines[j][3], sizeof(name));
4069 Q_CleanStr(name);
4070 // if the player name is a substring
4071 if (stristr(name, uiInfo.findPlayerName)) {
4072 // add to found server list if we have space (always leave space for a line with the number found)
4073 if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
4074 //
4075 Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
4076 uiInfo.pendingServerStatus.server[i].adrstr,
4077 sizeof(uiInfo.foundPlayerServerAddresses[0]));
4078 Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4079 uiInfo.pendingServerStatus.server[i].name,
4080 sizeof(uiInfo.foundPlayerServerNames[0]));
4081 uiInfo.numFoundPlayerServers++;
4082 }
4083 else {
4084 // can't add any more so we're done
4085 uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
4086 }
4087 }
4088 }
4089 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4090 sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4091 "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
4092 // retrieved the server status so reuse this spot
4093 uiInfo.pendingServerStatus.server[i].valid = qfalse;
4094 }
4095 }
4096 // if empty pending slot or timed out
4097 if (!uiInfo.pendingServerStatus.server[i].valid ||
4098 uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
4099 if (uiInfo.pendingServerStatus.server[i].valid) {
4100 numTimeOuts++;
4101 }
4102 // reset server status request for this address
4103 UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
4104 // reuse pending slot
4105 uiInfo.pendingServerStatus.server[i].valid = qfalse;
4106 // if we didn't try to get the status of all servers in the main browser yet
4107 if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
4108 uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
4109 trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
4110 uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
4111 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
4112 Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
4113 uiInfo.pendingServerStatus.server[i].valid = qtrue;
4114 uiInfo.pendingServerStatus.num++;
4115 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4116 sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4117 "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
4118 }
4119 }
4120 }
4121 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
4122 if (uiInfo.pendingServerStatus.server[i].valid) {
4123 break;
4124 }
4125 }
4126 // if still trying to retrieve server status info
4127 if (i < MAX_SERVERSTATUSREQUESTS) {
4128 uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
4129 }
4130 else {
4131 // add a line that shows the number of servers found
4132 if (!uiInfo.numFoundPlayerServers) {
4133 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
4134 }
4135 else {
4136 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
4137 "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
4138 uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
4139 }
4140 uiInfo.nextFindPlayerRefresh = 0;
4141 // show the server status info for the selected server
4142 UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
4143 }
4144 }
4145
4146 /*
4147 ==================
4148 UI_BuildServerStatus
4149 ==================
4150 */
UI_BuildServerStatus(qboolean force)4151 static void UI_BuildServerStatus(qboolean force) {
4152
4153 if (uiInfo.nextFindPlayerRefresh) {
4154 return;
4155 }
4156 if (!force) {
4157 if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
4158 return;
4159 }
4160 }
4161 else {
4162 Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
4163 uiInfo.serverStatusInfo.numLines = 0;
4164 // reset all server status requests
4165 trap_LAN_ServerStatus( NULL, NULL, 0);
4166 }
4167 if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
4168 return;
4169 }
4170 if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
4171 uiInfo.nextServerStatusRefresh = 0;
4172 UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
4173 }
4174 else {
4175 uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
4176 }
4177 }
4178
4179 /*
4180 ==================
4181 UI_FeederCount
4182 ==================
4183 */
UI_FeederCount(float feederID)4184 static int UI_FeederCount(float feederID) {
4185 if (feederID == FEEDER_HEADS) {
4186 return UI_HeadCountByTeam();
4187 } else if (feederID == FEEDER_Q3HEADS) {
4188 return uiInfo.q3HeadCount;
4189 } else if (feederID == FEEDER_CINEMATICS) {
4190 return uiInfo.movieCount;
4191 } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4192 return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
4193 } else if (feederID == FEEDER_SERVERS) {
4194 return uiInfo.serverStatus.numDisplayServers;
4195 } else if (feederID == FEEDER_SERVERSTATUS) {
4196 return uiInfo.serverStatusInfo.numLines;
4197 } else if (feederID == FEEDER_FINDPLAYER) {
4198 return uiInfo.numFoundPlayerServers;
4199 } else if (feederID == FEEDER_PLAYER_LIST) {
4200 if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
4201 uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
4202 UI_BuildPlayerList();
4203 }
4204 return uiInfo.playerCount;
4205 } else if (feederID == FEEDER_TEAM_LIST) {
4206 if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
4207 uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
4208 UI_BuildPlayerList();
4209 }
4210 return uiInfo.myTeamCount;
4211 } else if (feederID == FEEDER_MODS) {
4212 return uiInfo.modCount;
4213 } else if (feederID == FEEDER_DEMOS) {
4214 return uiInfo.demoCount;
4215 }
4216 return 0;
4217 }
4218
UI_SelectedMap(int index,int * actual)4219 static const char *UI_SelectedMap(int index, int *actual) {
4220 int i, c;
4221 c = 0;
4222 *actual = 0;
4223 for (i = 0; i < uiInfo.mapCount; i++) {
4224 if (uiInfo.mapList[i].active) {
4225 if (c == index) {
4226 *actual = i;
4227 return uiInfo.mapList[i].mapName;
4228 } else {
4229 c++;
4230 }
4231 }
4232 }
4233 return "";
4234 }
4235
UI_SelectedHead(int index,int * actual)4236 static const char *UI_SelectedHead(int index, int *actual) {
4237 int i, c;
4238 c = 0;
4239 *actual = 0;
4240 for (i = 0; i < uiInfo.characterCount; i++) {
4241 if (uiInfo.characterList[i].active) {
4242 if (c == index) {
4243 *actual = i;
4244 return uiInfo.characterList[i].name;
4245 } else {
4246 c++;
4247 }
4248 }
4249 }
4250 return "";
4251 }
4252
UI_GetIndexFromSelection(int actual)4253 static int UI_GetIndexFromSelection(int actual) {
4254 int i, c;
4255 c = 0;
4256 for (i = 0; i < uiInfo.mapCount; i++) {
4257 if (uiInfo.mapList[i].active) {
4258 if (i == actual) {
4259 return c;
4260 }
4261 c++;
4262 }
4263 }
4264 return 0;
4265 }
4266
UI_UpdatePendingPings(void)4267 static void UI_UpdatePendingPings( void ) {
4268 trap_LAN_ResetPings(ui_netSource.integer);
4269 uiInfo.serverStatus.refreshActive = qtrue;
4270 uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
4271
4272 }
4273
UI_FeederItemText(float feederID,int index,int column,qhandle_t * handle)4274 static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
4275 static char info[MAX_STRING_CHARS];
4276 static char hostname[1024];
4277 static char clientBuff[32];
4278 static int lastColumn = -1;
4279 static int lastTime = 0;
4280 *handle = -1;
4281 if (feederID == FEEDER_HEADS) {
4282 int actual;
4283 return UI_SelectedHead(index, &actual);
4284 } else if (feederID == FEEDER_Q3HEADS) {
4285 if (index >= 0 && index < uiInfo.q3HeadCount) {
4286 return uiInfo.q3HeadNames[index];
4287 }
4288 } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4289 int actual;
4290 return UI_SelectedMap(index, &actual);
4291 } else if (feederID == FEEDER_SERVERS) {
4292 if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
4293 int ping, game, punkbuster;
4294 if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
4295 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
4296 lastColumn = column;
4297 lastTime = uiInfo.uiDC.realTime;
4298 }
4299 ping = atoi(Info_ValueForKey(info, "ping"));
4300 if (ping == -1) {
4301 // if we ever see a ping that is out of date, do a server refresh
4302 // UI_UpdatePendingPings();
4303 }
4304 switch (column) {
4305 case SORT_HOST :
4306 if (ping <= 0) {
4307 return Info_ValueForKey(info, "addr");
4308 } else {
4309 if ( ui_netSource.integer == AS_LOCAL ) {
4310 Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
4311 Info_ValueForKey(info, "hostname"),
4312 netnames[atoi(Info_ValueForKey(info, "nettype"))] );
4313 return hostname;
4314 }
4315 else {
4316 Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
4317 return hostname;
4318 }
4319 }
4320 case SORT_MAP : return Info_ValueForKey(info, "mapname");
4321 case SORT_CLIENTS :
4322 Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
4323 return clientBuff;
4324 case SORT_GAME :
4325 game = atoi(Info_ValueForKey(info, "gametype"));
4326 if (game >= 0 && game < numTeamArenaGameTypes) {
4327 return teamArenaGameTypes[game];
4328 } else {
4329 return "Unknown";
4330 }
4331 case SORT_PING :
4332 if (ping <= 0) {
4333 return "...";
4334 } else {
4335 return Info_ValueForKey(info, "ping");
4336 }
4337 case SORT_PUNKBUSTER:
4338 punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
4339 if ( punkbuster ) {
4340 return "Yes";
4341 } else {
4342 return "No";
4343 }
4344 }
4345 }
4346 } else if (feederID == FEEDER_SERVERSTATUS) {
4347 if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
4348 if ( column >= 0 && column < 4 ) {
4349 return uiInfo.serverStatusInfo.lines[index][column];
4350 }
4351 }
4352 } else if (feederID == FEEDER_FINDPLAYER) {
4353 if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
4354 //return uiInfo.foundPlayerServerAddresses[index];
4355 return uiInfo.foundPlayerServerNames[index];
4356 }
4357 } else if (feederID == FEEDER_PLAYER_LIST) {
4358 if (index >= 0 && index < uiInfo.playerCount) {
4359 return uiInfo.playerNames[index];
4360 }
4361 } else if (feederID == FEEDER_TEAM_LIST) {
4362 if (index >= 0 && index < uiInfo.myTeamCount) {
4363 return uiInfo.teamNames[index];
4364 }
4365 } else if (feederID == FEEDER_MODS) {
4366 if (index >= 0 && index < uiInfo.modCount) {
4367 if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
4368 return uiInfo.modList[index].modDescr;
4369 } else {
4370 return uiInfo.modList[index].modName;
4371 }
4372 }
4373 } else if (feederID == FEEDER_CINEMATICS) {
4374 if (index >= 0 && index < uiInfo.movieCount) {
4375 return uiInfo.movieList[index];
4376 }
4377 } else if (feederID == FEEDER_DEMOS) {
4378 if (index >= 0 && index < uiInfo.demoCount) {
4379 return uiInfo.demoList[index];
4380 }
4381 }
4382 return "";
4383 }
4384
4385
UI_FeederItemImage(float feederID,int index)4386 static qhandle_t UI_FeederItemImage(float feederID, int index) {
4387 if (feederID == FEEDER_HEADS) {
4388 int actual;
4389 UI_SelectedHead(index, &actual);
4390 index = actual;
4391 if (index >= 0 && index < uiInfo.characterCount) {
4392 if (uiInfo.characterList[index].headImage == -1) {
4393 uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
4394 }
4395 return uiInfo.characterList[index].headImage;
4396 }
4397 } else if (feederID == FEEDER_Q3HEADS) {
4398 if (index >= 0 && index < uiInfo.q3HeadCount) {
4399 return uiInfo.q3HeadIcons[index];
4400 }
4401 } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
4402 int actual;
4403 UI_SelectedMap(index, &actual);
4404 index = actual;
4405 if (index >= 0 && index < uiInfo.mapCount) {
4406 if (uiInfo.mapList[index].levelShot == -1) {
4407 uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
4408 }
4409 return uiInfo.mapList[index].levelShot;
4410 }
4411 }
4412 return 0;
4413 }
4414
UI_FeederSelection(float feederID,int index)4415 static void UI_FeederSelection(float feederID, int index) {
4416 static char info[MAX_STRING_CHARS];
4417 if (feederID == FEEDER_HEADS) {
4418 int actual;
4419 UI_SelectedHead(index, &actual);
4420 index = actual;
4421 if (index >= 0 && index < uiInfo.characterCount) {
4422 trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
4423 trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
4424 updateModel = qtrue;
4425 }
4426 } else if (feederID == FEEDER_Q3HEADS) {
4427 if (index >= 0 && index < uiInfo.q3HeadCount) {
4428 trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
4429 trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
4430 updateModel = qtrue;
4431 }
4432 } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4433 int actual, map;
4434 map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
4435 if (uiInfo.mapList[map].cinematic >= 0) {
4436 trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
4437 uiInfo.mapList[map].cinematic = -1;
4438 }
4439 UI_SelectedMap(index, &actual);
4440 trap_Cvar_Set("ui_mapIndex", va("%d", index));
4441 ui_mapIndex.integer = index;
4442
4443 if (feederID == FEEDER_MAPS) {
4444 ui_currentMap.integer = actual;
4445 trap_Cvar_Set("ui_currentMap", va("%d", actual));
4446 uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
4447 UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
4448 trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
4449 updateOpponentModel = qtrue;
4450 } else {
4451 ui_currentNetMap.integer = actual;
4452 trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
4453 uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
4454 }
4455
4456 } else if (feederID == FEEDER_SERVERS) {
4457 const char *mapName = NULL;
4458 uiInfo.serverStatus.currentServer = index;
4459 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
4460 uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
4461 if (uiInfo.serverStatus.currentServerCinematic >= 0) {
4462 trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
4463 uiInfo.serverStatus.currentServerCinematic = -1;
4464 }
4465 mapName = Info_ValueForKey(info, "mapname");
4466 if (mapName && *mapName) {
4467 uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
4468 }
4469 } else if (feederID == FEEDER_SERVERSTATUS) {
4470 //
4471 } else if (feederID == FEEDER_FINDPLAYER) {
4472 uiInfo.currentFoundPlayerServer = index;
4473 //
4474 if ( index < uiInfo.numFoundPlayerServers-1) {
4475 // build a new server status for this server
4476 Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
4477 Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
4478 UI_BuildServerStatus(qtrue);
4479 }
4480 } else if (feederID == FEEDER_PLAYER_LIST) {
4481 uiInfo.playerIndex = index;
4482 } else if (feederID == FEEDER_TEAM_LIST) {
4483 uiInfo.teamIndex = index;
4484 } else if (feederID == FEEDER_MODS) {
4485 uiInfo.modIndex = index;
4486 } else if (feederID == FEEDER_CINEMATICS) {
4487 uiInfo.movieIndex = index;
4488 if (uiInfo.previewMovie >= 0) {
4489 trap_CIN_StopCinematic(uiInfo.previewMovie);
4490 }
4491 uiInfo.previewMovie = -1;
4492 } else if (feederID == FEEDER_DEMOS) {
4493 uiInfo.demoIndex = index;
4494 }
4495 }
4496
Team_Parse(char ** p)4497 static qboolean Team_Parse(char **p) {
4498 char *token;
4499 const char *tempStr;
4500 int i;
4501
4502 token = Com_ParseExt(p, qtrue);
4503
4504 if (token[0] != '{') {
4505 return qfalse;
4506 }
4507
4508 while ( 1 ) {
4509
4510 token = Com_ParseExt(p, qtrue);
4511
4512 if (Q_stricmp(token, "}") == 0) {
4513 return qtrue;
4514 }
4515
4516 if ( !token || token[0] == 0 ) {
4517 return qfalse;
4518 }
4519
4520 if (token[0] == '{') {
4521 // seven tokens per line, team name and icon, and 5 team member names
4522 if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
4523 return qfalse;
4524 }
4525
4526
4527 uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
4528 uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
4529 uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
4530 uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
4531
4532 uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
4533
4534 for (i = 0; i < TEAM_MEMBERS; i++) {
4535 uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
4536 if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
4537 return qfalse;
4538 }
4539 }
4540
4541 Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
4542 if (uiInfo.teamCount < MAX_TEAMS) {
4543 uiInfo.teamCount++;
4544 } else {
4545 Com_Printf("Too many teams, last team replaced!\n");
4546 }
4547 token = Com_ParseExt(p, qtrue);
4548 if (token[0] != '}') {
4549 return qfalse;
4550 }
4551 }
4552 }
4553
4554 return qfalse;
4555 }
4556
Character_Parse(char ** p)4557 static qboolean Character_Parse(char **p) {
4558 char *token;
4559 const char *tempStr;
4560
4561 token = Com_ParseExt(p, qtrue);
4562
4563 if (token[0] != '{') {
4564 return qfalse;
4565 }
4566
4567
4568 while ( 1 ) {
4569 token = Com_ParseExt(p, qtrue);
4570
4571 if (Q_stricmp(token, "}") == 0) {
4572 return qtrue;
4573 }
4574
4575 if ( !token || token[0] == 0 ) {
4576 return qfalse;
4577 }
4578
4579 if (token[0] == '{') {
4580 // two tokens per line, character name and sex
4581 if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
4582 return qfalse;
4583 }
4584
4585 uiInfo.characterList[uiInfo.characterCount].headImage = -1;
4586 uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
4587
4588 if (tempStr && (!Q_stricmp(tempStr, "female"))) {
4589 uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Janet"));
4590 } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
4591 uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("James"));
4592 } else {
4593 uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
4594 }
4595
4596 Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
4597 if (uiInfo.characterCount < MAX_HEADS) {
4598 uiInfo.characterCount++;
4599 } else {
4600 Com_Printf("Too many characters, last character replaced!\n");
4601 }
4602
4603 token = Com_ParseExt(p, qtrue);
4604 if (token[0] != '}') {
4605 return qfalse;
4606 }
4607 }
4608 }
4609
4610 return qfalse;
4611 }
4612
4613
Alias_Parse(char ** p)4614 static qboolean Alias_Parse(char **p) {
4615 char *token;
4616
4617 token = Com_ParseExt(p, qtrue);
4618
4619 if (token[0] != '{') {
4620 return qfalse;
4621 }
4622
4623 while ( 1 ) {
4624 token = Com_ParseExt(p, qtrue);
4625
4626 if (Q_stricmp(token, "}") == 0) {
4627 return qtrue;
4628 }
4629
4630 if ( !token || token[0] == 0 ) {
4631 return qfalse;
4632 }
4633
4634 if (token[0] == '{') {
4635 // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
4636 if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) {
4637 return qfalse;
4638 }
4639
4640 Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
4641 if (uiInfo.aliasCount < MAX_ALIASES) {
4642 uiInfo.aliasCount++;
4643 } else {
4644 Com_Printf("Too many aliases, last alias replaced!\n");
4645 }
4646
4647 token = Com_ParseExt(p, qtrue);
4648 if (token[0] != '}') {
4649 return qfalse;
4650 }
4651 }
4652 }
4653
4654 return qfalse;
4655 }
4656
4657
4658
4659 // mode
4660 // 0 - high level parsing
4661 // 1 - team parsing
4662 // 2 - character parsing
UI_ParseTeamInfo(const char * teamFile)4663 static void UI_ParseTeamInfo(const char *teamFile) {
4664 char *token;
4665 char *p;
4666 char *buff = NULL;
4667 //static int mode = 0; TTimo: unused
4668
4669 buff = GetMenuBuffer(teamFile);
4670 if (!buff) {
4671 return;
4672 }
4673
4674 p = buff;
4675
4676 while ( 1 ) {
4677 token = Com_ParseExt( &p, qtrue );
4678 if( !token || token[0] == 0 || token[0] == '}') {
4679 break;
4680 }
4681
4682 if ( Q_stricmp( token, "}" ) == 0 ) {
4683 break;
4684 }
4685
4686 if (Q_stricmp(token, "teams") == 0) {
4687
4688 if (Team_Parse(&p)) {
4689 continue;
4690 } else {
4691 break;
4692 }
4693 }
4694
4695 if (Q_stricmp(token, "characters") == 0) {
4696 Character_Parse(&p);
4697 }
4698
4699 if (Q_stricmp(token, "aliases") == 0) {
4700 Alias_Parse(&p);
4701 }
4702
4703 }
4704
4705 }
4706
4707
GameType_Parse(char ** p,qboolean join)4708 static qboolean GameType_Parse(char **p, qboolean join) {
4709 char *token;
4710
4711 token = Com_ParseExt(p, qtrue);
4712
4713 if (token[0] != '{') {
4714 return qfalse;
4715 }
4716
4717 if (join) {
4718 uiInfo.numJoinGameTypes = 0;
4719 } else {
4720 uiInfo.numGameTypes = 0;
4721 }
4722
4723 while ( 1 ) {
4724 token = Com_ParseExt(p, qtrue);
4725
4726 if (Q_stricmp(token, "}") == 0) {
4727 return qtrue;
4728 }
4729
4730 if ( !token || token[0] == 0 ) {
4731 return qfalse;
4732 }
4733
4734 if (token[0] == '{') {
4735 // two tokens per line, character name and sex
4736 if (join) {
4737 if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
4738 return qfalse;
4739 }
4740 } else {
4741 if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
4742 return qfalse;
4743 }
4744 }
4745
4746 if (join) {
4747 if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
4748 uiInfo.numJoinGameTypes++;
4749 } else {
4750 Com_Printf("Too many net game types, last one replace!\n");
4751 }
4752 } else {
4753 if (uiInfo.numGameTypes < MAX_GAMETYPES) {
4754 uiInfo.numGameTypes++;
4755 } else {
4756 Com_Printf("Too many game types, last one replace!\n");
4757 }
4758 }
4759
4760 token = Com_ParseExt(p, qtrue);
4761 if (token[0] != '}') {
4762 return qfalse;
4763 }
4764 }
4765 }
4766 return qfalse;
4767 }
4768
MapList_Parse(char ** p)4769 static qboolean MapList_Parse(char **p) {
4770 char *token;
4771
4772 token = Com_ParseExt(p, qtrue);
4773
4774 if (token[0] != '{') {
4775 return qfalse;
4776 }
4777
4778 uiInfo.mapCount = 0;
4779
4780 while ( 1 ) {
4781 token = Com_ParseExt(p, qtrue);
4782
4783 if (Q_stricmp(token, "}") == 0) {
4784 return qtrue;
4785 }
4786
4787 if ( !token || token[0] == 0 ) {
4788 return qfalse;
4789 }
4790
4791 if (token[0] == '{') {
4792 if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName)
4793 ||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
4794 return qfalse;
4795 }
4796
4797 if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
4798 return qfalse;
4799 }
4800
4801 uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
4802
4803 while (1) {
4804 token = Com_ParseExt(p, qtrue);
4805 if (token[0] >= '0' && token[0] <= '9') {
4806 uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
4807 if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
4808 return qfalse;
4809 }
4810 } else {
4811 break;
4812 }
4813 }
4814
4815 //mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
4816 //if (uiInfo.mapCount == 0) {
4817 // only load the first cinematic, selection loads the others
4818 // uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
4819 //}
4820 uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
4821 uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
4822
4823 if (uiInfo.mapCount < MAX_MAPS) {
4824 uiInfo.mapCount++;
4825 } else {
4826 Com_Printf("Too many maps, last one replaced!\n");
4827 }
4828 }
4829 }
4830 return qfalse;
4831 }
4832
UI_ParseGameInfo(const char * teamFile)4833 static void UI_ParseGameInfo(const char *teamFile) {
4834 char *token;
4835 char *p;
4836 char *buff = NULL;
4837 //int mode = 0; TTimo: unused
4838
4839 buff = GetMenuBuffer(teamFile);
4840 if (!buff) {
4841 return;
4842 }
4843
4844 p = buff;
4845
4846 while ( 1 ) {
4847 token = Com_ParseExt( &p, qtrue );
4848 if( !token || token[0] == 0 || token[0] == '}') {
4849 break;
4850 }
4851
4852 if ( Q_stricmp( token, "}" ) == 0 ) {
4853 break;
4854 }
4855
4856 if (Q_stricmp(token, "gametypes") == 0) {
4857
4858 if (GameType_Parse(&p, qfalse)) {
4859 continue;
4860 } else {
4861 break;
4862 }
4863 }
4864
4865 if (Q_stricmp(token, "joingametypes") == 0) {
4866
4867 if (GameType_Parse(&p, qtrue)) {
4868 continue;
4869 } else {
4870 break;
4871 }
4872 }
4873
4874 if (Q_stricmp(token, "maps") == 0) {
4875 // start a new menu
4876 MapList_Parse(&p);
4877 }
4878
4879 }
4880 }
4881
UI_Pause(qboolean b)4882 static void UI_Pause(qboolean b) {
4883 if (b) {
4884 // pause the game and set the ui keycatcher
4885 trap_Cvar_Set( "cl_paused", "1" );
4886 trap_Key_SetCatcher( KEYCATCH_UI );
4887 } else {
4888 // unpause the game and clear the ui keycatcher
4889 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4890 trap_Key_ClearStates();
4891 trap_Cvar_Set( "cl_paused", "0" );
4892 }
4893 }
4894
4895 #ifndef MISSIONPACK
UI_OwnerDraw_Width(int ownerDraw)4896 static int UI_OwnerDraw_Width(int ownerDraw) {
4897 return 0;
4898 }
4899 #endif
4900
UI_PlayCinematic(const char * name,float x,float y,float w,float h)4901 static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
4902 return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
4903 }
4904
UI_StopCinematic(int handle)4905 static void UI_StopCinematic(int handle) {
4906 if (handle >= 0) {
4907 trap_CIN_StopCinematic(handle);
4908 } else {
4909 handle = abs(handle);
4910 if (handle == UI_MAPCINEMATIC) {
4911 if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
4912 trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
4913 uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
4914 }
4915 } else if (handle == UI_NETMAPCINEMATIC) {
4916 if (uiInfo.serverStatus.currentServerCinematic >= 0) {
4917 trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
4918 uiInfo.serverStatus.currentServerCinematic = -1;
4919 }
4920 } else if (handle == UI_CLANCINEMATIC) {
4921 int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
4922 if (i >= 0 && i < uiInfo.teamCount) {
4923 if (uiInfo.teamList[i].cinematic >= 0) {
4924 trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
4925 uiInfo.teamList[i].cinematic = -1;
4926 }
4927 }
4928 }
4929 }
4930 }
4931
UI_DrawCinematic(int handle,float x,float y,float w,float h)4932 static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
4933 trap_CIN_SetExtents(handle, x, y, w, h);
4934 trap_CIN_DrawCinematic(handle);
4935 }
4936
UI_RunCinematicFrame(int handle)4937 static void UI_RunCinematicFrame(int handle) {
4938 trap_CIN_RunCinematic(handle);
4939 }
4940
4941
4942
4943 /*
4944 =================
4945 PlayerModel_BuildList
4946 =================
4947 */
UI_BuildQ3Model_List(void)4948 static void UI_BuildQ3Model_List( void )
4949 {
4950 int numdirs;
4951 int numfiles;
4952 char dirlist[2048];
4953 char filelist[2048];
4954 char skinname[MAX_QPATH];
4955 char scratch[256];
4956 char* dirptr;
4957 char* fileptr;
4958 int i;
4959 int j, k, dirty;
4960 int dirlen;
4961 int filelen;
4962
4963 uiInfo.q3HeadCount = 0;
4964
4965 // iterate directory of all player models
4966 numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
4967 dirptr = dirlist;
4968 for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
4969 {
4970 dirlen = strlen(dirptr);
4971
4972 if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
4973
4974 if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
4975 continue;
4976
4977 // iterate all skin files in directory
4978 numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
4979 fileptr = filelist;
4980 for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
4981 {
4982 filelen = strlen(fileptr);
4983
4984 Com_StripExtension(fileptr, skinname, sizeof(skinname));
4985
4986 // look for icon_????
4987 if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
4988 {
4989 if (Q_stricmp(skinname, "icon_default") == 0) {
4990 Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
4991 } else {
4992 Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
4993 }
4994 dirty = 0;
4995 for(k=0;k<uiInfo.q3HeadCount;k++) {
4996 if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
4997 dirty = 1;
4998 break;
4999 }
5000 }
5001 if (!dirty) {
5002 Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s", scratch);
5003 uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
5004 }
5005 }
5006
5007 }
5008 }
5009
5010 }
5011
5012
5013
5014 /*
5015 =================
5016 UI_Init
5017 =================
5018 */
_UI_Init(qboolean inGameLoad)5019 void _UI_Init( qboolean inGameLoad ) {
5020 const char *menuSet;
5021 int start;
5022
5023 //uiInfo.inGameLoad = inGameLoad;
5024
5025 UI_RegisterCvars();
5026 UI_InitMemory();
5027
5028 // cache redundant calulations
5029 trap_GetGlconfig( &uiInfo.uiDC.glconfig );
5030
5031 // for 640x480 virtualized screen
5032 uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
5033 uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
5034 if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
5035 // wide screen
5036 uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
5037 }
5038 else {
5039 // no wide screen
5040 uiInfo.uiDC.bias = 0;
5041 }
5042
5043
5044 //UI_Load();
5045 uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
5046 uiInfo.uiDC.setColor = &UI_SetColor;
5047 uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
5048 uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
5049 uiInfo.uiDC.drawText = &Text_Paint;
5050 uiInfo.uiDC.textWidth = &Text_Width;
5051 uiInfo.uiDC.textHeight = &Text_Height;
5052 uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
5053 uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
5054 uiInfo.uiDC.fillRect = &UI_FillRect;
5055 uiInfo.uiDC.drawRect = &_UI_DrawRect;
5056 uiInfo.uiDC.drawSides = &_UI_DrawSides;
5057 uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
5058 uiInfo.uiDC.clearScene = &trap_R_ClearScene;
5059 uiInfo.uiDC.drawSides = &_UI_DrawSides;
5060 uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
5061 uiInfo.uiDC.renderScene = &trap_R_RenderScene;
5062 uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
5063 uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
5064 uiInfo.uiDC.getValue = &UI_GetValue;
5065 uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
5066 uiInfo.uiDC.runScript = &UI_RunMenuScript;
5067 uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
5068 uiInfo.uiDC.setCVar = trap_Cvar_Set;
5069 uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
5070 uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
5071 uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
5072 uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
5073 uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
5074 uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
5075 uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
5076 uiInfo.uiDC.feederCount = &UI_FeederCount;
5077 uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
5078 uiInfo.uiDC.feederItemText = &UI_FeederItemText;
5079 uiInfo.uiDC.feederSelection = &UI_FeederSelection;
5080 uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
5081 uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
5082 uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
5083 uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
5084 uiInfo.uiDC.Error = &Com_Error;
5085 uiInfo.uiDC.Print = &Com_Printf;
5086 uiInfo.uiDC.Pause = &UI_Pause;
5087 uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
5088 uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
5089 uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
5090 uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
5091 uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
5092 uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
5093 uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
5094 uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
5095
5096 Init_Display(&uiInfo.uiDC);
5097
5098 String_Init();
5099
5100 uiInfo.uiDC.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
5101 uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
5102
5103 AssetCache();
5104
5105 start = trap_Milliseconds();
5106
5107 uiInfo.teamCount = 0;
5108 uiInfo.characterCount = 0;
5109 uiInfo.aliasCount = 0;
5110
5111 #ifdef PRE_RELEASE_TADEMO
5112 UI_ParseTeamInfo("demoteaminfo.txt");
5113 UI_ParseGameInfo("demogameinfo.txt");
5114 #else
5115 UI_ParseTeamInfo("teaminfo.txt");
5116 UI_LoadTeams();
5117 UI_ParseGameInfo("gameinfo.txt");
5118 #endif
5119
5120 menuSet = UI_Cvar_VariableString("ui_menuFiles");
5121 if (menuSet == NULL || menuSet[0] == '\0') {
5122 menuSet = "ui/menus.txt";
5123 }
5124
5125 #if 0
5126 if (uiInfo.inGameLoad) {
5127 UI_LoadMenus("ui/ingame.txt", qtrue);
5128 } else {
5129 }
5130 #else
5131 UI_LoadMenus(menuSet, qtrue);
5132 UI_LoadMenus("ui/ingame.txt", qfalse);
5133 #endif
5134
5135 Menus_CloseAll();
5136
5137 trap_LAN_LoadCachedServers();
5138 UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
5139
5140 UI_BuildQ3Model_List();
5141 UI_LoadBots();
5142
5143 // sets defaults for ui temp cvars
5144 uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
5145 uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
5146 trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
5147
5148 uiInfo.serverStatus.currentServerCinematic = -1;
5149 uiInfo.previewMovie = -1;
5150
5151 if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
5152 trap_Cvar_Set("s_volume", "0.8");
5153 trap_Cvar_Set("s_musicvolume", "0.5");
5154 trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
5155 }
5156
5157 trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
5158
5159 trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
5160 }
5161
5162
5163 /*
5164 =================
5165 UI_KeyEvent
5166 =================
5167 */
_UI_KeyEvent(int key,qboolean down)5168 void _UI_KeyEvent( int key, qboolean down ) {
5169
5170 if (Menu_Count() > 0) {
5171 menuDef_t *menu = Menu_GetFocused();
5172 if (menu) {
5173 if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
5174 Menus_CloseAll();
5175 } else {
5176 Menu_HandleKey(menu, key, down );
5177 }
5178 } else {
5179 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
5180 trap_Key_ClearStates();
5181 trap_Cvar_Set( "cl_paused", "0" );
5182 }
5183 }
5184
5185 //if ((s > 0) && (s != menu_null_sound)) {
5186 // trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
5187 //}
5188 }
5189
5190 /*
5191 =================
5192 UI_MouseEvent
5193 =================
5194 */
_UI_MouseEvent(int dx,int dy)5195 void _UI_MouseEvent( int dx, int dy )
5196 {
5197 // update mouse screen position
5198 uiInfo.uiDC.cursorx += dx;
5199 if (uiInfo.uiDC.cursorx < 0)
5200 uiInfo.uiDC.cursorx = 0;
5201 else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
5202 uiInfo.uiDC.cursorx = SCREEN_WIDTH;
5203
5204 uiInfo.uiDC.cursory += dy;
5205 if (uiInfo.uiDC.cursory < 0)
5206 uiInfo.uiDC.cursory = 0;
5207 else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
5208 uiInfo.uiDC.cursory = SCREEN_HEIGHT;
5209
5210 if (Menu_Count() > 0) {
5211 //menuDef_t *menu = Menu_GetFocused();
5212 //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
5213 Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
5214 }
5215
5216 }
5217
UI_LoadNonIngame(void)5218 void UI_LoadNonIngame( void ) {
5219 const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
5220 if (menuSet == NULL || menuSet[0] == '\0') {
5221 menuSet = "ui/menus.txt";
5222 }
5223 UI_LoadMenus(menuSet, qfalse);
5224 uiInfo.inGameLoad = qfalse;
5225 }
5226
_UI_SetActiveMenu(uiMenuCommand_t menu)5227 void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
5228 char buf[256];
5229
5230 // this should be the ONLY way the menu system is brought up
5231 // enusure minumum menu data is cached
5232 if (Menu_Count() > 0) {
5233 vec3_t v;
5234 v[0] = v[1] = v[2] = 0;
5235 switch ( menu ) {
5236 case UIMENU_NONE:
5237 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
5238 trap_Key_ClearStates();
5239 trap_Cvar_Set( "cl_paused", "0" );
5240 Menus_CloseAll();
5241
5242 return;
5243 case UIMENU_MAIN:
5244 trap_Cvar_Set( "sv_killserver", "1" );
5245 trap_Key_SetCatcher( KEYCATCH_UI );
5246 //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
5247 //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
5248 if (uiInfo.inGameLoad) {
5249 UI_LoadNonIngame();
5250 }
5251 Menus_CloseAll();
5252 Menus_ActivateByName("main");
5253 trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
5254 if (strlen(buf)) {
5255 if (!ui_singlePlayerActive.integer) {
5256 Menus_ActivateByName("error_popmenu");
5257 } else {
5258 trap_Cvar_Set("com_errorMessage", "");
5259 }
5260 }
5261 return;
5262 case UIMENU_TEAM:
5263 trap_Key_SetCatcher( KEYCATCH_UI );
5264 Menus_ActivateByName("team");
5265 return;
5266 case UIMENU_NEED_CD:
5267 // no cd check in TA
5268 //trap_Key_SetCatcher( KEYCATCH_UI );
5269 //Menus_ActivateByName("needcd");
5270 //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
5271 return;
5272 case UIMENU_BAD_CD_KEY:
5273 // no cd check in TA
5274 //trap_Key_SetCatcher( KEYCATCH_UI );
5275 //Menus_ActivateByName("badcd");
5276 //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
5277 return;
5278 case UIMENU_POSTGAME:
5279 trap_Cvar_Set( "sv_killserver", "1" );
5280 trap_Key_SetCatcher( KEYCATCH_UI );
5281 if (uiInfo.inGameLoad) {
5282 UI_LoadNonIngame();
5283 }
5284 Menus_CloseAll();
5285 Menus_ActivateByName("endofgame");
5286 //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
5287 return;
5288 case UIMENU_INGAME:
5289 trap_Cvar_Set( "cl_paused", "1" );
5290 trap_Key_SetCatcher( KEYCATCH_UI );
5291 UI_BuildPlayerList();
5292 Menus_CloseAll();
5293 Menus_ActivateByName("ingame");
5294 return;
5295 }
5296 }
5297 }
5298
_UI_IsFullscreen(void)5299 qboolean _UI_IsFullscreen( void ) {
5300 return Menus_AnyFullScreenVisible();
5301 }
5302
5303
5304
5305 static connstate_t lastConnState;
5306 static char lastLoadingText[MAX_INFO_VALUE];
5307
UI_ReadableSize(char * buf,int bufsize,int value)5308 static void UI_ReadableSize ( char *buf, int bufsize, int value )
5309 {
5310 if (value > 1024*1024*1024 ) { // gigs
5311 Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
5312 Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
5313 (value % (1024*1024*1024))*100 / (1024*1024*1024) );
5314 } else if (value > 1024*1024 ) { // megs
5315 Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
5316 Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
5317 (value % (1024*1024))*100 / (1024*1024) );
5318 } else if (value > 1024 ) { // kilos
5319 Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
5320 } else { // bytes
5321 Com_sprintf( buf, bufsize, "%d bytes", value );
5322 }
5323 }
5324
5325 // Assumes time is in msec
UI_PrintTime(char * buf,int bufsize,int time)5326 static void UI_PrintTime ( char *buf, int bufsize, int time ) {
5327 time /= 1000; // change to seconds
5328
5329 if (time > 3600) { // in the hours range
5330 Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
5331 } else if (time > 60) { // mins
5332 Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
5333 } else { // secs
5334 Com_sprintf( buf, bufsize, "%d sec", time );
5335 }
5336 }
5337
Text_PaintCenter(float x,float y,float scale,vec4_t color,const char * text,float adjust)5338 void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
5339 int len = Text_Width(text, scale, 0);
5340 Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
5341 }
5342
Text_PaintCenter_AutoWrapped(float x,float y,float xmax,float ystep,float scale,vec4_t color,const char * str,float adjust)5343 void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
5344 int width;
5345 char *s1,*s2,*s3;
5346 char c_bcp;
5347 char buf[1024];
5348
5349 if (!str || str[0]=='\0')
5350 return;
5351
5352 Q_strncpyz(buf, str, sizeof(buf));
5353 s1 = s2 = s3 = buf;
5354
5355 while (1) {
5356 do {
5357 s3++;
5358 } while (*s3!=' ' && *s3!='\0');
5359 c_bcp = *s3;
5360 *s3 = '\0';
5361 width = Text_Width(s1, scale, 0);
5362 *s3 = c_bcp;
5363 if (width > xmax) {
5364 if (s1==s2)
5365 {
5366 // fuck, don't have a clean cut, we'll overflow
5367 s2 = s3;
5368 }
5369 *s2 = '\0';
5370 Text_PaintCenter(x, y, scale, color, s1, adjust);
5371 y += ystep;
5372 if (c_bcp == '\0')
5373 {
5374 // that was the last word
5375 // we could start a new loop, but that wouldn't be much use
5376 // even if the word is too long, we would overflow it (see above)
5377 // so just print it now if needed
5378 s2++;
5379 if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
5380 Text_PaintCenter(x, y, scale, color, s2, adjust);
5381 break;
5382 }
5383 s2++;
5384 s1 = s2;
5385 s3 = s2;
5386 }
5387 else
5388 {
5389 s2 = s3;
5390 if (c_bcp == '\0') // we reached the end
5391 {
5392 Text_PaintCenter(x, y, scale, color, s1, adjust);
5393 break;
5394 }
5395 }
5396 }
5397 }
5398
UI_DisplayDownloadInfo(const char * downloadName,float centerPoint,float yStart,float scale)5399 static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
5400 static char dlText[] = "Downloading:";
5401 static char etaText[] = "Estimated time left:";
5402 static char xferText[] = "Transfer rate:";
5403
5404 int downloadSize, downloadCount, downloadTime;
5405 char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
5406 int xferRate;
5407 int leftWidth;
5408 const char *s;
5409
5410 downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
5411 downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
5412 downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
5413
5414 leftWidth = 320;
5415
5416 UI_SetColor(colorWhite);
5417 Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
5418 Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
5419 Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
5420
5421 if (downloadSize > 0) {
5422 s = va( "%s (%d%%)", downloadName,
5423 (int)( (float)downloadCount * 100.0f / downloadSize ) );
5424 } else {
5425 s = downloadName;
5426 }
5427
5428 Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
5429
5430 UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
5431 UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
5432
5433 if (downloadCount < 4096 || !downloadTime) {
5434 Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
5435 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5436 } else {
5437 if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
5438 xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
5439 } else {
5440 xferRate = 0;
5441 }
5442 UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
5443
5444 // Extrapolate estimated completion time
5445 if (downloadSize && xferRate) {
5446 int n = downloadSize / xferRate; // estimated time for entire d/l in secs
5447
5448 // We do it in K (/1024) because we'd overflow around 4MB
5449 UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
5450 (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
5451
5452 Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
5453 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5454 } else {
5455 Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
5456 if (downloadSize) {
5457 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5458 } else {
5459 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
5460 }
5461 }
5462
5463 if (xferRate) {
5464 Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
5465 }
5466 }
5467 }
5468
5469 /*
5470 ========================
5471 UI_DrawConnectScreen
5472
5473 This will also be overlaid on the cgame info screen during loading
5474 to prevent it from blinking away too rapidly on local or lan games.
5475 ========================
5476 */
UI_DrawConnectScreen(qboolean overlay)5477 void UI_DrawConnectScreen( qboolean overlay ) {
5478 char *s;
5479 uiClientState_t cstate;
5480 char info[MAX_INFO_VALUE];
5481 char text[256];
5482 float centerPoint, yStart, scale;
5483
5484 menuDef_t *menu = Menus_FindByName("Connect");
5485
5486
5487 if ( !overlay && menu ) {
5488 Menu_Paint(menu, qtrue);
5489 }
5490
5491 if (!overlay) {
5492 centerPoint = 320;
5493 yStart = 130;
5494 scale = 0.5f;
5495 } else {
5496 centerPoint = 320;
5497 yStart = 32;
5498 scale = 0.6f;
5499 return;
5500 }
5501
5502 // see what information we should display
5503 trap_GetClientState( &cstate );
5504
5505 info[0] = '\0';
5506 if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
5507 Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
5508 }
5509
5510 if (!Q_stricmp(cstate.servername,"localhost")) {
5511 Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
5512 } else {
5513 strcpy(text, va("Connecting to %s", cstate.servername));
5514 Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
5515 }
5516
5517 // display global MOTD at bottom
5518 Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
5519 // print any server info (server full, bad version, etc)
5520 if ( cstate.connState < CA_CONNECTED ) {
5521 Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
5522 }
5523
5524 if ( lastConnState > cstate.connState ) {
5525 lastLoadingText[0] = '\0';
5526 }
5527 lastConnState = cstate.connState;
5528
5529 switch ( cstate.connState ) {
5530 case CA_CONNECTING:
5531 s = va("Awaiting connection...%i", cstate.connectPacketCount);
5532 break;
5533 case CA_CHALLENGING:
5534 s = va("Awaiting challenge...%i", cstate.connectPacketCount);
5535 break;
5536 case CA_CONNECTED: {
5537 char downloadName[MAX_INFO_VALUE];
5538
5539 trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
5540 if (*downloadName) {
5541 UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
5542 return;
5543 }
5544 }
5545 s = "Awaiting gamestate...";
5546 break;
5547 case CA_LOADING:
5548 return;
5549 case CA_PRIMED:
5550 return;
5551 default:
5552 return;
5553 }
5554
5555
5556 if (Q_stricmp(cstate.servername,"localhost")) {
5557 Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
5558 }
5559
5560 // password required / connection rejected information goes here
5561 }
5562
5563
5564 /*
5565 ================
5566 cvars
5567 ================
5568 */
5569
5570 typedef struct {
5571 vmCvar_t *vmCvar;
5572 char *cvarName;
5573 char *defaultString;
5574 int cvarFlags;
5575 } cvarTable_t;
5576
5577 vmCvar_t ui_ffa_fraglimit;
5578 vmCvar_t ui_ffa_timelimit;
5579
5580 vmCvar_t ui_tourney_fraglimit;
5581 vmCvar_t ui_tourney_timelimit;
5582
5583 vmCvar_t ui_team_fraglimit;
5584 vmCvar_t ui_team_timelimit;
5585 vmCvar_t ui_team_friendly;
5586
5587 vmCvar_t ui_ctf_capturelimit;
5588 vmCvar_t ui_ctf_timelimit;
5589 vmCvar_t ui_ctf_friendly;
5590
5591 vmCvar_t ui_arenasFile;
5592 vmCvar_t ui_botsFile;
5593 vmCvar_t ui_spScores1;
5594 vmCvar_t ui_spScores2;
5595 vmCvar_t ui_spScores3;
5596 vmCvar_t ui_spScores4;
5597 vmCvar_t ui_spScores5;
5598 vmCvar_t ui_spAwards;
5599 vmCvar_t ui_spVideos;
5600 vmCvar_t ui_spSkill;
5601
5602 vmCvar_t ui_spSelection;
5603
5604 vmCvar_t ui_browserMaster;
5605 vmCvar_t ui_browserGameType;
5606 vmCvar_t ui_browserSortKey;
5607 vmCvar_t ui_browserShowFull;
5608 vmCvar_t ui_browserShowEmpty;
5609
5610 vmCvar_t ui_brassTime;
5611 vmCvar_t ui_drawCrosshair;
5612 vmCvar_t ui_drawCrosshairNames;
5613 vmCvar_t ui_marks;
5614
5615 vmCvar_t ui_server1;
5616 vmCvar_t ui_server2;
5617 vmCvar_t ui_server3;
5618 vmCvar_t ui_server4;
5619 vmCvar_t ui_server5;
5620 vmCvar_t ui_server6;
5621 vmCvar_t ui_server7;
5622 vmCvar_t ui_server8;
5623 vmCvar_t ui_server9;
5624 vmCvar_t ui_server10;
5625 vmCvar_t ui_server11;
5626 vmCvar_t ui_server12;
5627 vmCvar_t ui_server13;
5628 vmCvar_t ui_server14;
5629 vmCvar_t ui_server15;
5630 vmCvar_t ui_server16;
5631
5632 vmCvar_t ui_cdkeychecked;
5633
5634 vmCvar_t ui_redteam;
5635 vmCvar_t ui_redteam1;
5636 vmCvar_t ui_redteam2;
5637 vmCvar_t ui_redteam3;
5638 vmCvar_t ui_redteam4;
5639 vmCvar_t ui_redteam5;
5640 vmCvar_t ui_blueteam;
5641 vmCvar_t ui_blueteam1;
5642 vmCvar_t ui_blueteam2;
5643 vmCvar_t ui_blueteam3;
5644 vmCvar_t ui_blueteam4;
5645 vmCvar_t ui_blueteam5;
5646 vmCvar_t ui_teamName;
5647 vmCvar_t ui_dedicated;
5648 vmCvar_t ui_gameType;
5649 vmCvar_t ui_netGameType;
5650 vmCvar_t ui_actualNetGameType;
5651 vmCvar_t ui_joinGameType;
5652 vmCvar_t ui_netSource;
5653 vmCvar_t ui_serverFilterType;
5654 vmCvar_t ui_opponentName;
5655 vmCvar_t ui_menuFiles;
5656 vmCvar_t ui_currentTier;
5657 vmCvar_t ui_currentMap;
5658 vmCvar_t ui_currentNetMap;
5659 vmCvar_t ui_mapIndex;
5660 vmCvar_t ui_currentOpponent;
5661 vmCvar_t ui_selectedPlayer;
5662 vmCvar_t ui_selectedPlayerName;
5663 vmCvar_t ui_lastServerRefresh_0;
5664 vmCvar_t ui_lastServerRefresh_1;
5665 vmCvar_t ui_lastServerRefresh_2;
5666 vmCvar_t ui_lastServerRefresh_3;
5667 vmCvar_t ui_singlePlayerActive;
5668 vmCvar_t ui_scoreAccuracy;
5669 vmCvar_t ui_scoreImpressives;
5670 vmCvar_t ui_scoreExcellents;
5671 vmCvar_t ui_scoreCaptures;
5672 vmCvar_t ui_scoreDefends;
5673 vmCvar_t ui_scoreAssists;
5674 vmCvar_t ui_scoreGauntlets;
5675 vmCvar_t ui_scoreScore;
5676 vmCvar_t ui_scorePerfect;
5677 vmCvar_t ui_scoreTeam;
5678 vmCvar_t ui_scoreBase;
5679 vmCvar_t ui_scoreTimeBonus;
5680 vmCvar_t ui_scoreSkillBonus;
5681 vmCvar_t ui_scoreShutoutBonus;
5682 vmCvar_t ui_scoreTime;
5683 vmCvar_t ui_captureLimit;
5684 vmCvar_t ui_fragLimit;
5685 vmCvar_t ui_smallFont;
5686 vmCvar_t ui_bigFont;
5687 vmCvar_t ui_findPlayer;
5688 vmCvar_t ui_Q3Model;
5689 vmCvar_t ui_hudFiles;
5690 vmCvar_t ui_recordSPDemo;
5691 vmCvar_t ui_realCaptureLimit;
5692 vmCvar_t ui_realWarmUp;
5693 vmCvar_t ui_serverStatusTimeOut;
5694
5695 static cvarTable_t cvarTable[] = {
5696 { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
5697 { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
5698
5699 { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
5700 { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
5701
5702 { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
5703 { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
5704 { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
5705
5706 { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
5707 { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
5708 { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
5709
5710 { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
5711 { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
5712 { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
5713 { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
5714 { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
5715 { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
5716 { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
5717 { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
5718 { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
5719 { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
5720
5721 { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
5722
5723 { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
5724 { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
5725 { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
5726 { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
5727 { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
5728
5729 { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
5730 { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
5731 { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
5732 { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
5733
5734 { &ui_server1, "server1", "", CVAR_ARCHIVE },
5735 { &ui_server2, "server2", "", CVAR_ARCHIVE },
5736 { &ui_server3, "server3", "", CVAR_ARCHIVE },
5737 { &ui_server4, "server4", "", CVAR_ARCHIVE },
5738 { &ui_server5, "server5", "", CVAR_ARCHIVE },
5739 { &ui_server6, "server6", "", CVAR_ARCHIVE },
5740 { &ui_server7, "server7", "", CVAR_ARCHIVE },
5741 { &ui_server8, "server8", "", CVAR_ARCHIVE },
5742 { &ui_server9, "server9", "", CVAR_ARCHIVE },
5743 { &ui_server10, "server10", "", CVAR_ARCHIVE },
5744 { &ui_server11, "server11", "", CVAR_ARCHIVE },
5745 { &ui_server12, "server12", "", CVAR_ARCHIVE },
5746 { &ui_server13, "server13", "", CVAR_ARCHIVE },
5747 { &ui_server14, "server14", "", CVAR_ARCHIVE },
5748 { &ui_server15, "server15", "", CVAR_ARCHIVE },
5749 { &ui_server16, "server16", "", CVAR_ARCHIVE },
5750 { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
5751 { &ui_new, "ui_new", "0", CVAR_TEMP },
5752 { &ui_debug, "ui_debug", "0", CVAR_TEMP },
5753 { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
5754 { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
5755 { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
5756 { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
5757 { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
5758 { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
5759 { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
5760 { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
5761 { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
5762 { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
5763 { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
5764 { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
5765 { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
5766 { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
5767 { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
5768 { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
5769 { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
5770 { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
5771 { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
5772 { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
5773 { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
5774 { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
5775 { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
5776 { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
5777 { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
5778 { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
5779 { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
5780 { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
5781 { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
5782 { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
5783 { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
5784 { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
5785 { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
5786 { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
5787 { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
5788 { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
5789 { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
5790 { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
5791 { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
5792 { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
5793 { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
5794 { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
5795 { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
5796 { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
5797 { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
5798 { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
5799 { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
5800 { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
5801 { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
5802 { &ui_fragLimit, "ui_fragLimit", "10", 0},
5803 { &ui_captureLimit, "ui_captureLimit", "5", 0},
5804 { &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
5805 { &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
5806 { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
5807 { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
5808 { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
5809 { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
5810 { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
5811 { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
5812 { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
5813 { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
5814
5815 };
5816
5817 static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
5818
5819
5820 /*
5821 =================
5822 UI_RegisterCvars
5823 =================
5824 */
UI_RegisterCvars(void)5825 void UI_RegisterCvars( void ) {
5826 int i;
5827 cvarTable_t *cv;
5828
5829 for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
5830 trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
5831 }
5832 }
5833
5834 /*
5835 =================
5836 UI_UpdateCvars
5837 =================
5838 */
UI_UpdateCvars(void)5839 void UI_UpdateCvars( void ) {
5840 int i;
5841 cvarTable_t *cv;
5842
5843 for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
5844 trap_Cvar_Update( cv->vmCvar );
5845 }
5846 }
5847
5848
5849 /*
5850 =================
5851 ArenaServers_StopRefresh
5852 =================
5853 */
UI_StopServerRefresh(void)5854 static void UI_StopServerRefresh( void )
5855 {
5856 int count;
5857
5858 if (!uiInfo.serverStatus.refreshActive) {
5859 // not currently refreshing
5860 return;
5861 }
5862 uiInfo.serverStatus.refreshActive = qfalse;
5863 Com_Printf("%d servers listed in browser with %d players.\n",
5864 uiInfo.serverStatus.numDisplayServers,
5865 uiInfo.serverStatus.numPlayersOnServers);
5866 count = trap_LAN_GetServerCount(ui_netSource.integer);
5867 if (count - uiInfo.serverStatus.numDisplayServers > 0) {
5868 Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
5869 count - uiInfo.serverStatus.numDisplayServers,
5870 (int) trap_Cvar_VariableValue("cl_maxPing"));
5871 }
5872
5873 }
5874
5875 /*
5876 =================
5877 ArenaServers_MaxPing
5878 =================
5879 */
5880 #ifndef MISSIONPACK
ArenaServers_MaxPing(void)5881 static int ArenaServers_MaxPing( void ) {
5882 int maxPing;
5883
5884 maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
5885 if( maxPing < 100 ) {
5886 maxPing = 100;
5887 }
5888 return maxPing;
5889 }
5890 #endif
5891
5892 /*
5893 =================
5894 UI_DoServerRefresh
5895 =================
5896 */
UI_DoServerRefresh(void)5897 static void UI_DoServerRefresh( void )
5898 {
5899 qboolean wait = qfalse;
5900
5901 if (!uiInfo.serverStatus.refreshActive) {
5902 return;
5903 }
5904 if (ui_netSource.integer != AS_FAVORITES) {
5905 if (ui_netSource.integer == AS_LOCAL) {
5906 if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
5907 wait = qtrue;
5908 }
5909 } else {
5910 if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
5911 wait = qtrue;
5912 }
5913 }
5914 }
5915
5916 if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
5917 if (wait) {
5918 return;
5919 }
5920 }
5921
5922 // if still trying to retrieve pings
5923 if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
5924 uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
5925 } else if (!wait) {
5926 // get the last servers in the list
5927 UI_BuildServerDisplayList(2);
5928 // stop the refresh
5929 UI_StopServerRefresh();
5930 }
5931 //
5932 UI_BuildServerDisplayList(qfalse);
5933 }
5934
5935 /*
5936 =================
5937 UI_StartServerRefresh
5938 =================
5939 */
UI_StartServerRefresh(qboolean full)5940 static void UI_StartServerRefresh(qboolean full)
5941 {
5942 char *ptr;
5943
5944 qtime_t q;
5945 trap_RealTime(&q);
5946 trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
5947
5948 if (!full) {
5949 UI_UpdatePendingPings();
5950 return;
5951 }
5952
5953 uiInfo.serverStatus.refreshActive = qtrue;
5954 uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
5955 // clear number of displayed servers
5956 uiInfo.serverStatus.numDisplayServers = 0;
5957 uiInfo.serverStatus.numPlayersOnServers = 0;
5958 // mark all servers as visible so we store ping updates for them
5959 trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
5960 // reset all the pings
5961 trap_LAN_ResetPings(ui_netSource.integer);
5962 //
5963 if( ui_netSource.integer == AS_LOCAL ) {
5964 trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
5965 uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
5966 return;
5967 }
5968
5969 uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
5970 if( ui_netSource.integer == AS_GLOBAL ) {
5971
5972 ptr = UI_Cvar_VariableString("debug_protocol");
5973 if (strlen(ptr)) {
5974 trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %s full empty\n", ptr));
5975 }
5976 else {
5977 trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %d full empty\n", (int)trap_Cvar_VariableValue( "protocol" ) ) );
5978 }
5979 }
5980 }
5981
5982