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