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 #include "ui_local.h"
24 
25 /*
26 ===============================================================================
27 
28 CONNECTION SCREEN
29 
30 ===============================================================================
31 */
32 
33 qboolean	passwordNeeded = qtrue;
34 menufield_s passwordField;
35 
36 static connstate_t	lastConnState;
37 static char			lastLoadingText[MAX_INFO_VALUE];
38 
UI_ReadableSize(char * buf,int bufsize,int value)39 static void UI_ReadableSize ( char *buf, int bufsize, int value )
40 {
41 	if (value > 1024*1024*1024 ) { // gigs
42 		Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
43 		Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
44 			(value % (1024*1024*1024))*100 / (1024*1024*1024) );
45 	} else if (value > 1024*1024 ) { // megs
46 		Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
47 		Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
48 			(value % (1024*1024))*100 / (1024*1024) );
49 	} else if (value > 1024 ) { // kilos
50 		Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
51 	} else { // bytes
52 		Com_sprintf( buf, bufsize, "%d bytes", value );
53 	}
54 }
55 
56 // Assumes time is in msec
UI_PrintTime(char * buf,int bufsize,int time)57 static void UI_PrintTime ( char *buf, int bufsize, int time ) {
58 	time /= 1000;  // change to seconds
59 
60 	if (time > 3600) { // in the hours range
61 		Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
62 	} else if (time > 60) { // mins
63 		Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
64 	} else  { // secs
65 		Com_sprintf( buf, bufsize, "%d sec", time );
66 	}
67 }
68 
UI_DisplayDownloadInfo(const char * downloadName)69 static void UI_DisplayDownloadInfo( const char *downloadName ) {
70 	static char dlText[]	= "Downloading:";
71 	static char etaText[]	= "Estimated time left:";
72 	static char xferText[]	= "Transfer rate:";
73 
74 	int downloadSize, downloadCount, downloadTime;
75 	char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
76 	int xferRate;
77 	int width, leftWidth;
78 	int style = UI_LEFT|UI_SMALLFONT|UI_DROPSHADOW;
79 	const char *s;
80 
81 	downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
82 	downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
83 	downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
84 
85 	leftWidth = width = UI_ProportionalStringWidth( dlText ) * UI_ProportionalSizeScale( style );
86 	width = UI_ProportionalStringWidth( etaText ) * UI_ProportionalSizeScale( style );
87 	if (width > leftWidth) leftWidth = width;
88 	width = UI_ProportionalStringWidth( xferText ) * UI_ProportionalSizeScale( style );
89 	if (width > leftWidth) leftWidth = width;
90 	leftWidth += 16;
91 
92 	UI_DrawProportionalString( 8, 128, dlText, style, color_white );
93 	UI_DrawProportionalString( 8, 160, etaText, style, color_white );
94 	UI_DrawProportionalString( 8, 224, xferText, style, color_white );
95 
96 	if (downloadSize > 0) {
97 		s = va( "%s (%d%%)", downloadName, (int)( (float)downloadCount * 100.0f / downloadSize ) );
98 	} else {
99 		s = downloadName;
100 	}
101 
102 	UI_DrawProportionalString( leftWidth, 128, s, style, color_white );
103 
104 	UI_ReadableSize( dlSizeBuf,		sizeof dlSizeBuf,		downloadCount );
105 	UI_ReadableSize( totalSizeBuf,	sizeof totalSizeBuf,	downloadSize );
106 
107 	if (downloadCount < 4096 || !downloadTime) {
108 		UI_DrawProportionalString( leftWidth, 160, "estimating", style, color_white );
109 		UI_DrawProportionalString( leftWidth, 192,
110 			va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
111 	} else {
112 	  if ( (uis.realtime - downloadTime) / 1000) {
113 			xferRate = downloadCount / ((uis.realtime - downloadTime) / 1000);
114 		  //xferRate = (int)( ((float)downloadCount) / elapsedTime);
115 		} else {
116 			xferRate = 0;
117 		}
118 
119 		UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
120 
121 		// Extrapolate estimated completion time
122 		if (downloadSize && xferRate) {
123 			int n = downloadSize / xferRate; // estimated time for entire d/l in secs
124 
125 			// We do it in K (/1024) because we'd overflow around 4MB
126 			n = (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000;
127 
128 			UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf, n );
129 				//(n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
130 
131 			UI_DrawProportionalString( leftWidth, 160,
132 				dlTimeBuf, style, color_white );
133 			UI_DrawProportionalString( leftWidth, 192,
134 				va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
135 		} else {
136 			UI_DrawProportionalString( leftWidth, 160,
137 				"estimating", style, color_white );
138 			if (downloadSize) {
139 				UI_DrawProportionalString( leftWidth, 192,
140 					va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
141 			} else {
142 				UI_DrawProportionalString( leftWidth, 192,
143 					va("(%s copied)", dlSizeBuf), style, color_white );
144 			}
145 		}
146 
147 		if (xferRate) {
148 			UI_DrawProportionalString( leftWidth, 224,
149 				va("%s/Sec", xferRateBuf), style, color_white );
150 		}
151 	}
152 }
153 
154 /*
155 ========================
156 UI_DrawConnectScreen
157 
158 This will also be overlaid on the cgame info screen during loading
159 to prevent it from blinking away too rapidly on local or lan games.
160 ========================
161 */
UI_DrawConnectScreen(qboolean overlay)162 void UI_DrawConnectScreen( qboolean overlay ) {
163 	char			*s;
164 	uiClientState_t	cstate;
165 	char			info[MAX_INFO_VALUE];
166 
167 	Menu_Cache();
168 
169 	if ( !overlay ) {
170 		// draw the dialog background
171 		UI_SetColor( color_white );
172 		UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
173 	}
174 
175 	// see what information we should display
176 	trap_GetClientState( &cstate );
177 
178 	info[0] = '\0';
179 	if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
180 		UI_DrawProportionalString( 320, 16, va( "Loading %s", Info_ValueForKey( info, "mapname" ) ), UI_BIGFONT|UI_CENTER|UI_DROPSHADOW, color_white );
181 	}
182 
183 	UI_DrawProportionalString( 320, 64, va("Connecting to %s", cstate.servername), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
184 	//UI_DrawProportionalString( 320, 96, "Press Esc to abort", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
185 
186 	// display global MOTD at bottom
187 	UI_DrawProportionalString( SCREEN_WIDTH/2, SCREEN_HEIGHT-32,
188 		Info_ValueForKey( cstate.updateInfoString, "motd" ), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
189 
190 	// print any server info (server full, bad version, etc)
191 	if ( cstate.connState < CA_CONNECTED ) {
192 		UI_DrawProportionalString_AutoWrapped( 320, 192, 630, 20, cstate.messageString, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
193 	}
194 
195 #if 0
196 	// display password field
197 	if ( passwordNeeded ) {
198 		s_ingame_menu.x = SCREEN_WIDTH * 0.50 - 128;
199 		s_ingame_menu.nitems = 0;
200 		s_ingame_menu.wrapAround = qtrue;
201 
202 		passwordField.generic.type = MTYPE_FIELD;
203 		passwordField.generic.name = "Password:";
204 		passwordField.generic.callback = 0;
205 		passwordField.generic.x		= 10;
206 		passwordField.generic.y		= 180;
207 		Field_Clear( &passwordField.field );
208 		passwordField.width = 256;
209 		passwordField.field.widthInChars = 16;
210 		Q_strncpyz( passwordField.field.buffer, Cvar_VariableString("password"),
211 			sizeof(passwordField.field.buffer) );
212 
213 		Menu_AddItem( &s_ingame_menu, ( void * ) &s_customize_player_action );
214 
215 		MField_Draw( &passwordField );
216 	}
217 #endif
218 
219 	if ( lastConnState > cstate.connState ) {
220 		lastLoadingText[0] = '\0';
221 	}
222 	lastConnState = cstate.connState;
223 
224 	switch ( cstate.connState ) {
225 	case CA_CONNECTING:
226 		s = va("Awaiting challenge...%i", cstate.connectPacketCount);
227 		break;
228 	case CA_CHALLENGING:
229 		s = va("Awaiting connection...%i", cstate.connectPacketCount);
230 		break;
231 	case CA_CONNECTED: {
232 		char downloadName[MAX_INFO_VALUE];
233 
234 			trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
235 			if (*downloadName) {
236 				UI_DisplayDownloadInfo( downloadName );
237 				return;
238 			}
239 		}
240 		s = "Awaiting gamestate...";
241 		break;
242 	case CA_LOADING:
243 		return;
244 	case CA_PRIMED:
245 		return;
246 	default:
247 		return;
248 	}
249 
250 	UI_DrawProportionalString( 320, 128, s, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, color_white );
251 
252 	// password required / connection rejected information goes here
253 }
254 
255 
256 /*
257 ===================
258 UI_KeyConnect
259 ===================
260 */
UI_KeyConnect(int key)261 void UI_KeyConnect( int key ) {
262 	if ( key == K_ESCAPE ) {
263 		trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
264 		return;
265 	}
266 }
267