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