/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2007 HermitWorks Entertainment Corporation This file is part of the Space Trader source code. The Space Trader source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Space Trader source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the Space Trader source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "ui_local.h" /* ======================================================================= USER INTERFACE MAIN ======================================================================= */ uiInfo_t uiInfo; static const char *MonthAbbrev[] = { "Jan","Feb","Mar", "Apr","May","Jun", "Jul","Aug","Sep", "Oct","Nov","Dec" }; #define MAX_MENU_STACKS 64 menuStackDef_t ui_menuStack; menuStackDef_t cg_menuStack; static void UI_StartServerRefresh( void ); static void UI_StopServerRefresh( void ); static void UI_DoServerRefresh( void ); extern void Save_Item( fileHandle_t f, itemDef_t * item ); /* ================ vmMain This is the only way control passes into the module. This must be the very first function compiled into the .qvm file ================ */ vmCvar_t ui_new; vmCvar_t ui_debug; vmCvar_t ui_initialized; vmCvar_t ui_spacetrader; vmCvar_t ui_tooltipmode; vmCvar_t ui_drawMenu; void _UI_Init( qboolean ); void _UI_Shutdown( qboolean ); void _UI_KeyEvent( int key, qboolean down ); int _UI_MouseEvent( int dx, int dy ); void _UI_Refresh( int realtime ); qboolean _UI_IsFullscreen( void ); extern int debug_cgmenu; extern int UI_GlobalInt(); int QDECL 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 ) { REF_PARAM( arg3 ); REF_PARAM( arg4 ); REF_PARAM( arg5 ); REF_PARAM( arg6 ); REF_PARAM( arg7 ); REF_PARAM( arg8 ); REF_PARAM( arg9 ); REF_PARAM( arg10 ); REF_PARAM( arg11 ); if ( debug_cgmenu ) UI_SetMenuStack( &cg_menuStack ); else UI_SetMenuStack( &ui_menuStack ); switch ( command ) { case UI_GETAPIVERSION: return UI_API_VERSION; case UI_INIT: _UI_Init(arg0); uiInfo.clientNum = arg1; return 0; case UI_GAMEINIT: { UI_ST_exec( UI_ST_INIT_GAME ); } return 0; case UI_SHUTDOWN: _UI_Shutdown(arg0); return 0; case UI_KEY_EVENT: _UI_KeyEvent( arg1, arg2 ); return 0; case UI_MOUSE_EVENT: return _UI_MouseEvent( arg1, arg2 ); case UI_REFRESH: if ( (GS_INPLAY || !ui_spacetrader.integer) && !(trap_Key_GetCatcher() & KEYCATCH_UI) && !_UI_IsFullscreen() ) UI_SetMenuStack( &cg_menuStack ); _UI_Refresh( arg1 ); return 0; case UI_IS_FULLSCREEN: return _UI_IsFullscreen(); case UI_SET_ACTIVE_MENU: _UI_SetActiveMenu( arg0 ); return 0; case UI_CONSOLE_COMMAND: return UI_ConsoleCommand(arg0); case UI_DRAW_CONNECT_SCREEN: UI_DrawConnectScreen( arg0 ); return 0; case UI_REPORT_HIGHSCORE_RESPONSE: UI_ST_exec(UI_ST_REPORT_HIGHSCORE_RESPONSE, arg0); return 0; case UI_AUTHORIZED: UI_ST_exec(UI_ST_AUTHORIZED, arg0, arg1); return 0; case UI_SERVER_ERRORMESSAGE: UI_ST_exec(UI_ST_SERVER_ERRORMESSAGE, arg0 ); return 0; case UI_GLOBAL_INT: return UI_GlobalInt(); } return -1; } void AssetCache() { int n; for( n = 0; n < NUM_CROSSHAIRS; n++ ) { uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) ); } //REMOVE SOUND //uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse); uiInfo.uiDC.Assets.shipModel = trap_R_RegisterModel( ASSET_PLANETMODEL ); uiInfo.uiDC.Assets.planetModel = trap_R_RegisterModel( ASSET_PLANETMODEL ); uiInfo.uiDC.Assets.orbit = trap_R_RegisterShaderNoMip( "ui/assets/orbit" ); uiInfo.uiDC.Assets.orbitSel = trap_R_RegisterShaderNoMip( "ui/assets/orbitsel" ); uiInfo.uiDC.Assets.star = trap_R_RegisterShaderNoMip( "ui/assets/star" ); uiInfo.uiDC.Assets.menu = trap_R_RegisterShaderNoMip( "ui/assets/menubrushed" ); uiInfo.uiDC.Assets.menubar = trap_R_RegisterShaderNoMip( "ui/assets/menubar" ); uiInfo.uiDC.Assets.sbThumb = trap_R_RegisterShaderNoMip( "ui/assets/scrollarrows" ); uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( "ui/assets/slider" ); uiInfo.uiDC.Assets.lineshadow = trap_R_RegisterShaderNoMip( "ui/assets/pricegraph_shadow" ); uiInfo.uiDC.Assets.redbar = trap_R_RegisterShaderNoMip( "ui/assets/redalpha" ); uiInfo.uiDC.Assets.radar_player = trap_R_RegisterShaderNoMip( "radarPlayer" ); uiInfo.uiDC.Assets.radar_bot = trap_R_RegisterShaderNoMip( "radarBot" ); } void _UI_DrawSides(float x, float y, float w, float h, float size) { UI_AdjustFrom640( &x, &y, &w, &h ); size *= uiInfo.uiDC.glconfig.xscale; trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); } void _UI_DrawTopBottom(float x, float y, float w, float h, float size) { UI_AdjustFrom640( &x, &y, &w, &h ); size *= uiInfo.uiDC.glconfig.yscale; trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); } /* ================ UI_DrawRect Coordinates are 640*480 virtual values ================= */ void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) { trap_R_SetColor( color ); _UI_DrawTopBottom(x, y, width, height, size); _UI_DrawSides(x, y, width, height, size); trap_R_SetColor( NULL ); } /* ================= _UI_Refresh ================= */ void UI_DrawCenteredPic(qhandle_t image, int w, int h) { int x, y; x = (SCREEN_WIDTH - w) >> 1; y = (SCREEN_HEIGHT - h) >> 1; UI_DrawHandlePic((float)x, (float)y, (float)w, (float)h, image); } int frameCount = 0; int startTime; #define UI_FPS_FRAMES 4 void _UI_Refresh( int realtime ) { static int index; static int previousTimes[UI_FPS_FRAMES]; //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) { // return; //} uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime; uiInfo.uiDC.realTime = realtime; previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime; index++; if ( index > UI_FPS_FRAMES ) { int i, total; // average multiple frames together to smooth changes out a bit total = 0; for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) { total += previousTimes[i]; } if ( !total ) { total = 1; } uiInfo.uiDC.FPS = (float)(1000 * UI_FPS_FRAMES / total); } UI_ST_exec( UI_ST_REFRESH ); UI_UpdateCvars(); UI_Effects_Update(); if ( ui_drawMenu.integer ) { if (Menu_Count() > 0) { // paint all the menus Menu_PaintAll(); // refresh server browser list UI_DoServerRefresh(); } } UI_Effects_Draw( 0 ); UI_ST_exec( UI_ST_PAINT ); // tool tips if ( ui_tooltipmode.integer == 2 && UI_Effect_IsAlive( uiInfo.tooltip ) ) { float xb = DC->glconfig.xbias / DC->glconfig.xscale; rectDef_t r; effectDef_t * e = UI_Effect_GetEffect( uiInfo.tooltip ); r.x = e->rect.x + (float)DC->cursorx; r.y = e->rect.y + (float)DC->cursory; r.w = e->rect.w; r.h = e->rect.h; // don't let rect go off screen if ( r.x < -xb ) r.x = -xb; if ( r.y < 0.0f ) r.y = 0.0f; if ( r.x + r.w > 640.0f + xb ) r.x = 640.0f + xb - r.w; if ( r.y + r.h > 480.0f ) r.y = 480.0f - r.h; UI_Effect_SetJustRect( uiInfo.tooltip, &r ); } } /* ================= _UI_Shutdown ================= */ void _UI_Shutdown( qboolean save_menustack ) { if ( save_menustack ) { int i; char info[ MAX_INFO_STRING ]; info[ 0 ] = '\0'; for ( i=0; iwindow.name ); Q_strcat( info, sizeof(info), " " ); } trap_Cvar_Set( "ui_menustack", info ); } else trap_Cvar_Set( "ui_menustack", "" ); } static int QDECL SortEffects( const void *arg1, const void *arg2 ) { effectDef_t ** a = (effectDef_t**)arg1; effectDef_t ** b = (effectDef_t**)arg2; return Q_stricmp( (*a)->name, (*b)->name ); } qboolean Asset_Parse(int handle) { pc_token_t token; const char *tempStr; cachedAssets_t * a = &uiInfo.uiDC.Assets; if (!trap_PC_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "{") != 0) { return qfalse; } for( ; ; ) { memset(&token, 0, sizeof(pc_token_t)); if (!trap_PC_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "}") == 0) { break; } switch( SWITCHSTRING( token.string ) ) { case CS('f','o','n','t'): if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->font = trap_R_RegisterFont(tempStr); break; case CS('m','e','n','u'): { switch( SWITCHSTRING( token.string + 4 ) ) { // menuEnterSound case CS('e','n','t','e'): if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->menuEnterSound = trap_S_RegisterSound( tempStr, qfalse ); break; // menuExitSound case CS('e','x','i','t'): if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->menuExitSound = trap_S_RegisterSound( tempStr, qfalse ); break; // menuBuzzSound case CS('b','u','z','z'): if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse ); break; } } break; case CS('d','i','n','g'): { int i = token.string[ 4 ] - '0'; if ( i < 0 || i > 4 ) return qfalse; if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->dings[ i ] = trap_S_RegisterSound( tempStr, qfalse ); } break; // itemFocusSound case CS('i','t','e','m'): if (!PC_String_Parse(handle, &tempStr)) { return qfalse; } a->itemFocusSound = trap_S_RegisterSound( tempStr, qfalse ); break; // cursor case CS('c','u','r','s'): if (!PC_String_Parse(handle, &a->cursorStr)) { return qfalse; } a->cursor = trap_R_RegisterShaderNoMip( a->cursorStr); break; case CS('f','a','d','e'): { switch( SWITCHSTRING( token.string + 4 ) ) { // fadeClamp case CS('c','l','a','m'): if (!PC_Float_Parse(handle, &a->fadeClamp)) { return qfalse; } break; // fadeCycle case CS('c','y','c','l'): if (!PC_Int_Parse(handle, &a->fadeCycle)) { return qfalse; } break; // fadeAmount case CS('a','m','o','u'): if (!PC_Float_Parse(handle, &a->fadeAmount)) { return qfalse; } break; } } break; // effectDef_t case CS('e','f','f','e'): { if ( a->effectCount < lengthof(a->effects) ) { effectDef_t * effect = UI_Alloc( sizeof(effectDef_t) ); a->effects[ a->effectCount++ ] = effect; if ( !Effect_Parse( handle, effect ) ) return qfalse; } } break; } } qsort( a->effects, a->effectCount, sizeof(a->effects[0]), SortEffects ); return qtrue; } void UI_ParseStrings( const char * stringFile ) { int handle; handle = trap_PC_LoadSource( stringFile ); if ( !handle ) { return; } for ( ;; ) { const char * id; const char * src; int index; if ( !PC_String_Parse( handle, &id ) ) break; if ( !PC_String_Parse( handle, &src ) ) break; index = trap_SQL_Compile( src ); sql( "INSERT INTO strings(index,name) VALUES(?1,$2);", "ite", index,id ); } trap_PC_FreeSource(handle); } void UI_ParseMenu(const char *menuFile) { int handle; pc_token_t token; handle = trap_PC_LoadSource(menuFile); if (!handle) { return; } for( ; ; ) { memset(&token, 0, sizeof(pc_token_t)); if (!trap_PC_ReadToken( handle, &token )) { break; } //if ( Q_stricmp( token, "{" ) ) { // Com_Printf( "Missing { in menu file\n" ); // break; //} //if ( menuCount == MAX_MENUS ) { // Com_Printf( "Too many menus!\n" ); // break; //} if ( token.string[0] == '}' ) { break; } if (Q_stricmp(token.string, "assetGlobalDef") == 0) { if (Asset_Parse(handle)) { continue; } else { break; } } if (Q_stricmp(token.string, "menudef") == 0) { // start a new menu Menu_New(handle, menuFile ); } } trap_PC_FreeSource(handle); } #ifdef DEVELOPER int FindThing( const char * text, const char * tag, const char * markerBegin, const char * markerEnd, const char * thingname, const char ** begin, const char ** end ) { const char * def = 0; int braces=0; int found; int brace=0; const char * a = 0; const char * b = 0; char * t = 0; const char * last = 0; for ( found=0; !(found && brace==braces); ) { last = text; t = COM_ParseExt( &text, qtrue ); if ( t[ 0 ] == '\0' ) break; if ( !Q_stricmp( t, tag ) ) { t = COM_ParseExt( &text, qtrue ); if ( t[ 0 ] != '{' ) return 0; def = text; brace = ++braces; if ( !thingname ) // no name take first one found = 1; } if ( t[ 0 ] == '{' ) braces++; if ( t[ 0 ] == '}' ) braces--; if ( braces == brace+1 && !Q_stricmp( t, "name" ) ) { t = COM_ParseExt( &text, qtrue ); if ( !Q_stricmp( t, thingname ) ) found = 1; } if ( found && thingname && !Q_stricmp( t, "itemDef" ) ) break; } if ( found ) { a = Q_strstr( def, text-def, markerBegin ); b = Q_strstr( def, text-def, markerEnd ); if ( a < def || a > text ) a = last; if ( b >= def && b < text ) { b += strlen( markerEnd ); } else b = last; *begin = a; *end = b; return 1; } return 0; } static void writef( fileHandle_t f, const char * t ) { trap_FS_Write( t, strlen(t), f ); } static void writef_rect( fileHandle_t f, const char * name, rectDef_t * r ) { writef( f, va("%s\t\t%d %d %d %d\n", name, (int)r->x, (int)r->y, (int)r->w, (int)r->h ) ); } static void writef_int( fileHandle_t f, const char * name, int i ) { writef( f, va("%s\t\t%d\n", name, i ) ); } void Save_Menu( menuDef_t * menu, const char * filename ) { char buffer[ 65535 * 4 ]; fileHandle_t f; const char * start; const char * end; int i,len; const char * search; const char * menuMarkerBegin = "\n\t\t//--editor.menu.begin--\n"; const char * menuMarkerEnd = "\t\t//--editor.menu.end--\n"; const char * itemMarkerBegin = "\n\t\t\t//--editor.item.begin--\n"; const char * itemMarkerEnd = "\t\t\t//--editor.item.end--\n"; float x = uiInfo.uiDC.glconfig.xbias / uiInfo.uiDC.glconfig.xscale; len = trap_FS_FOpenFile( filename, &f, FS_READ ); if ( !f ) { trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) ); return; } if ( len >= sizeof(buffer) ) { trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, sizeof(buffer) ) ); trap_FS_FCloseFile( f ); return; } trap_FS_Read( buffer, len, f ); buffer[len] = 0; if ( !FindThing( buffer, "menuDef", menuMarkerBegin, menuMarkerEnd, menu->window.name, &start, &end ) ) return; trap_FS_FCloseFile( f ); trap_FS_FOpenFile( filename, &f, FS_UPDATE ); // write everything previous to menu trap_FS_Write( buffer, start-buffer, f ); // write menu writef( f, menuMarkerBegin ); menu->window.rectClient = menu->window.rect; if ( menu->window.flags & WINDOW_ALIGNLEFT ) { menu->window.rectClient.x += x; } else if ( menu->window.flags & WINDOW_ALIGNRIGHT ) { menu->window.rectClient.x -= x; } else if ( menu->window.flags & WINDOW_ALIGNWIDTH ) { float right = (menu->window.rectClient.x + menu->window.rectClient.w) - x*2.0f; menu->window.rectClient.x += x; menu->window.rectClient.w = right - menu->window.rectClient.x; } writef_rect( f, "\t\trect", &menu->window.rectClient ); writef_int( f, "\t\tstyle", menu->window.style ); writef( f, menuMarkerEnd ); search = end; // write items for ( i=0; iitemCount; i++ ) { const char * itemBegin; const char * itemEnd; itemDef_t * item = menu->items[ i ]; if ( !FindThing( search, "itemDef", itemMarkerBegin, itemMarkerEnd, 0, &itemBegin, &itemEnd ) ) { trap_Print( va( S_COLOR_RED "couldn't finish saving menu file %s\n", filename ) ); break; } // write everything before item trap_FS_Write( search, itemBegin-search, f ); writef( f, itemMarkerBegin ); Save_Item( f, item ); writef( f, itemMarkerEnd ); search = itemEnd; } // write everything after menu trap_FS_Write( search, len-(search-buffer), f ); trap_FS_FCloseFile( f ); } #endif qboolean Load_Menu(int handle) { pc_token_t token; if (!trap_PC_ReadToken(handle, &token)) return qfalse; if (token.string[0] != '{') { return qfalse; } for( ; ; ) { if (!trap_PC_ReadToken(handle, &token)) return qfalse; if ( token.string[0] == 0 ) { return qfalse; } if ( token.string[0] == '}' ) { return qtrue; } UI_ParseMenu(token.string); } } void UI_LoadMenus(const char *menuFile, qboolean reset) { pc_token_t token; int handle; int start; start = trap_Milliseconds(); handle = trap_PC_LoadSource( menuFile ); if (!handle) { trap_Error( ERR_DROP, va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) ); handle = trap_PC_LoadSource( "ui/menus.txt" ); if (!handle) { trap_Error( ERR_DROP, va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n", menuFile ) ); } } ui_new.integer = 1; if (reset) { Menu_Reset(); } for( ; ; ) { if (!trap_PC_ReadToken(handle, &token)) break; if( token.string[0] == 0 || token.string[0] == '}') { break; } if ( token.string[0] == '}' ) { break; } if (Q_stricmp(token.string, "loadmenu") == 0) { if (Load_Menu(handle)) { continue; } else { break; } } } Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start); trap_PC_FreeSource( handle ); } static void UI_DrawCrosshair( itemDef_t * item, vec4_t color ) { rectDef_t * rect = &item->window.rect; vec4_t hcolor; REF_PARAM( color ); hcolor[0] = trap_Cvar_VariableValue("cg_crosshairColorR"); hcolor[1] = trap_Cvar_VariableValue("cg_crosshairColorG"); hcolor[2] = trap_Cvar_VariableValue("cg_crosshairColorB"); hcolor[3] = trap_Cvar_VariableValue("cg_crosshairColorA"); trap_R_SetColor( hcolor ); if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) { uiInfo.currentCrosshair = 0; } UI_DrawHandlePic( rect->x + item->textdivx + 8.0f, rect->y, rect->h, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]); trap_R_SetColor( NULL ); } const char* UI_GetOwnerText( int id ) { if( id == 0 ) return ""; switch ( id ) { case 0: return 0; case BG_TOOLTIP: { int i; for ( i=ui_menuStack.count-1; i>=0; i-- ) { menuDef_t * menu = ui_menuStack.m[ i ]; if ( menu && menu->focusItem && menu->focusItem->tooltip ) { if ( sql( "SELECT index FROM strings SEARCH name $;", "t", menu->focusItem->tooltip ) ) { int tooltip = sqlint(0); sqldone(); return UI_ST_getString( tooltip ); } } } return 0; } break; case UI_KEYBINDSTATUS: return (Display_KeyBindPending())?"Waiting for new key... Press ESCAPE to cancel":"Press ENTER or CLICK to change, Press BACKSPACE to clear"; default: return UI_ST_getString( id ); } } static void UI_OwnerDraw( itemDef_t * item, vec4_t color ) { switch( item->window.ownerDraw ) { case UI_CROSSHAIR: UI_DrawCrosshair( item, color); break; default: UI_ST_exec( UI_ST_OWNERDRAW_PAINT, item ); break; } } static qboolean UI_Crosshair_HandleKey( int flags, int key ) { REF_PARAM( flags ); if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { if (key == K_MOUSE2) { uiInfo.currentCrosshair--; } else { uiInfo.currentCrosshair++; } if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) { uiInfo.currentCrosshair = 0; } else if (uiInfo.currentCrosshair < 0) { uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1; } trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair)); return qtrue; } return qfalse; } /* UNREFERENCED LOCAL FUNCTION static qboolean UI_NumericRange_HandleKey( int* val, float *special, int key, int min, int max, int bigAmt ) { if( key & K_CHAR_FLAG ) { key &= ~K_CHAR_FLAG; if( key < '0' || key > '9' ) return qfalse; if( *special == 0 ) { *val = key - '0'; *special = 1; } else { *val = atoi( va( "%i%c", *val, key ) ); } } else { switch( key ) { case K_BACKSPACE: if( *special != 0 ) { char *s = va( "%i", *val ); int l = strlen( s ); if( l ) { s[l - 1] = '\0'; if( l == 1 ) *special = 0; } *val = atoi( s ); } break; case K_MWHEELUP: case K_UPARROW: (*val)++; *special = 0; break; case K_MWHEELDOWN: case K_DOWNARROW: (*val)--; *special = 0; break; case K_RIGHTARROW: *val += bigAmt; *special = 0; break; case K_LEFTARROW: *val -= bigAmt; *special = 0; break; case K_HOME: *val = min; *special = 0; break; case K_END: *val = max; *special = 0; break; default: return qfalse; } } return qtrue; } */ static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, int key) { switch (ownerDraw) { case UI_CROSSHAIR: UI_Crosshair_HandleKey(flags, key); break; } return qfalse; } static qboolean UI_OwnerDrawHandleMouseMove( itemDef_t * item, float x, float y ) { switch( item->window.ownerDraw ) { default: UI_ST_exec( UI_ST_OWNERDRAW_MOUSEMOVE, item, x,y ); break; } return qfalse; } static bool Validate_Name( const char *s ) { if( !Info_Validate( s ) ) return false; for( ; *s; s++ ) { switch( *s ) { case '\\': return false; } } return true; } static void UI_Login() { int logged_in = trap_Cvar_VariableInt( "ui_logged_in" ); if ( logged_in != -2 && logged_in != 1 ) { char username[MAX_NAME_LENGTH]; char password[MAX_NAME_LENGTH]; trap_Cvar_VariableStringBuffer("ui_username", username, MAX_NAME_LENGTH); trap_Cvar_VariableStringBuffer("ui_password", password, MAX_NAME_LENGTH); if ( username[0] == '\0' || password[ 0 ] == '\0' ) { trap_Cvar_Set( "ui_logged_in", "0" ); } else { trap_Cvar_Set( "ui_logged_in", "-2" ); trap_Cmd_ExecuteText( EXEC_APPEND, va("login \"%s\" \"%s\";\n", username, password) ); } } } static void UI_Update( const char *name ) { int val = (int)trap_Cvar_VariableValue( name ); if ( name[ 0 ] == 'u' && name[ 1 ] == 'i' && name[ 2 ] == '_' ) { switch( SWITCHSTRING( name+3 ) ) { // ui_sethost case CS('s','e','t','h'): { if (Info_Validate( UI_Cvar_VariableString( "ui_hostname" ) ) ) { trap_Cvar_Set( "sv_hostname", UI_Cvar_VariableString( "ui_hostname" ) ); } } break; // ui_gethost case CS('g','e','t','h'): { trap_Cvar_Set( "ui_hostname", UI_Cvar_VariableString("sv_hostname")); } break; // ui_SetName case CS('S','e','t','N'): { if( Validate_Name( UI_Cvar_VariableString( "ui_Name" ) ) ) { trap_Cvar_Set( "name", UI_Cvar_VariableString( "ui_Name" ) ); } else { //keep name and ui_name in sync trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString( "name" ) ); } } break; // ui_setRate case CS('s','e','t','r'): { float rate = trap_Cvar_VariableValue( "rate" ); if( rate >= 5000 ) { trap_Cvar_Set( "cl_maxpackets", "30" ); trap_Cvar_Set( "cl_packetdup", "1" ); } else if( rate >= 4000 ) { trap_Cvar_Set( "cl_maxpackets", "15" ); trap_Cvar_Set( "cl_packetdup", "2" ); // favor less prediction errors when there's packet loss } else { trap_Cvar_Set( "cl_maxpackets", "15" ); trap_Cvar_Set( "cl_packetdup", "1" ); // favor lower bandwidth } } break; // ui_GetName case CS('g','e','t','n'): { trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name")); } break; // ui_glCustom case CS('g','l','c','u'): { switch( val ) { case 0: // high quality trap_Cvar_SetValue( "r_fullScreen", 1 ); trap_Cvar_SetValue( "r_subdivisions", 4 ); trap_Cvar_SetValue( "r_vertexlight", 0 ); trap_Cvar_SetValue( "r_lodbias", 0 ); trap_Cvar_SetValue( "r_colorbits", 32 ); trap_Cvar_SetValue( "r_depthbits", 24 ); trap_Cvar_SetValue( "r_picmip", 0 ); trap_Cvar_SetValue( "r_mode", 5 ); trap_Cvar_SetValue( "r_fastSky", 0 ); trap_Cvar_SetValue( "r_inGameVideo", 1 ); trap_Cvar_SetValue( "cg_shadows", 1 ); trap_Cvar_SetValue( "cg_brassTime", 2500 ); trap_Cvar_Set( "r_texturemode", "LinearMipLinear" ); break; case 1: // normal trap_Cvar_SetValue( "r_fullScreen", 1 ); trap_Cvar_SetValue( "r_subdivisions", 12 ); trap_Cvar_SetValue( "r_vertexlight", 0 ); trap_Cvar_SetValue( "r_lodbias", 0 ); trap_Cvar_SetValue( "r_colorbits", 0 ); trap_Cvar_SetValue( "r_depthbits", 24 ); trap_Cvar_SetValue( "r_picmip", 1 ); trap_Cvar_SetValue( "r_mode", 4 ); trap_Cvar_SetValue( "r_fastSky", 0 ); trap_Cvar_SetValue( "r_inGameVideo", 1 ); trap_Cvar_SetValue( "cg_brassTime", 2500 ); trap_Cvar_Set( "r_texturemode", "LinearMipLinear" ); trap_Cvar_SetValue( "cg_shadows", 0 ); break; case 2: // fast trap_Cvar_SetValue( "r_fullScreen", 1 ); trap_Cvar_SetValue( "r_subdivisions", 8 ); trap_Cvar_SetValue( "r_vertexlight", 0 ); trap_Cvar_SetValue( "r_lodbias", 1 ); trap_Cvar_SetValue( "r_colorbits", 0 ); trap_Cvar_SetValue( "r_depthbits", 0 ); trap_Cvar_SetValue( "r_picmip", 1 ); trap_Cvar_SetValue( "r_mode", 3 ); trap_Cvar_SetValue( "cg_shadows", 0 ); trap_Cvar_SetValue( "r_fastSky", 1 ); trap_Cvar_SetValue( "r_inGameVideo", 0 ); trap_Cvar_SetValue( "cg_brassTime", 0 ); trap_Cvar_Set( "r_texturemode", "LinearMipLinear" ); trap_Cvar_Set( "r_fsaa", "0"); break; case 3: // fastest trap_Cvar_SetValue( "r_fullScreen", 1 ); trap_Cvar_SetValue( "r_subdivisions", 20 ); trap_Cvar_SetValue( "r_vertexlight", 1 ); trap_Cvar_SetValue( "r_lodbias", 2 ); trap_Cvar_SetValue( "r_colorbits", 16 ); trap_Cvar_SetValue( "r_depthbits", 16 ); trap_Cvar_SetValue( "r_mode", 3 ); trap_Cvar_SetValue( "r_picmip", 2 ); trap_Cvar_SetValue( "cg_shadows", 0 ); trap_Cvar_SetValue( "cg_brassTime", 0 ); trap_Cvar_SetValue( "r_fastSky", 1 ); trap_Cvar_SetValue( "r_inGameVideo", 0 ); trap_Cvar_Set( "r_texturemode", "LinearMipNearest" ); trap_Cvar_Set( "r_fsaa", "0"); break; } } break; // ui_mousePitch case CS('m','o','u','s'): { trap_Cvar_SetValue( "m_pitch", val ? -0.022F : 0.022F ); } break; } } else if ( name[ 0 ] == 'r' && name[ 1 ] == '_' ) { switch( SWITCHSTRING( name+2 ) ) { // r_colorbits case CS('c','o','l','o'): { switch( val ) { case 0: trap_Cvar_SetValue( "r_depthbits", 0 ); trap_Cvar_SetValue( "r_stencilbits", 0 ); break; case 16: trap_Cvar_SetValue( "r_depthbits", 16 ); trap_Cvar_SetValue( "r_stencilbits", 0 ); break; default: trap_Cvar_SetValue( "r_depthbits", 24 ); break; } } break; // r_lodbias case CS('l','o','d','b'): { switch( val ) { case 0: trap_Cvar_SetValue( "r_subdivisions", 4 ); break; case 1: trap_Cvar_SetValue( "r_subdivisions", 12 ); break; case 2: trap_Cvar_SetValue( "r_subdivisions", 20 ); break; } } break; } } } static void UI_RunMenuScript( const char **args ) { const char *name, *name2; if( String_Parse( args, &name ) ) { if ( name[ 0 ] == 's' && name[ 1 ] == 't' && name[ 2 ] == '_' ) { // menu script commands prefixed with 'st_' are destined for rules engine... UI_ST_exec( UI_ST_SCRIPTCOMMAND, name+3, args ); return; } else if( Q_stricmp( name, "resetDefaults" ) == 0 ) { trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); Controls_SetDefaults(); trap_Cvar_Set("com_introPlayed", "1" ); trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); } else if( Q_stricmp( name, "saveControls" ) == 0 ) { Controls_SetConfig(qtrue); } else if( Q_stricmp( name, "loadControls" ) == 0 ) { Controls_GetConfig(); } else if( Q_stricmp( name, "clearError" ) == 0 ) { trap_Cvar_Set("com_errorMessage", ""); } else if( Q_stricmp( name, "RefreshServers" ) == 0 ) { UI_StartServerRefresh(); } else if( Q_stricmp( name, "RefreshFilter" ) == 0 ) { UI_StartServerRefresh(); } else if( Q_stricmp( name, "StopRefresh" ) == 0 ) { UI_StopServerRefresh(); } else if( Q_stricmp( name, "UpdateFilter" ) == 0 ) { if (ui_netSource.integer == AS_LOCAL) { UI_StartServerRefresh(); } } else if( Q_stricmp( name, "JoinServer" ) == 0 ) { if ( sql( "SELECT addr FROM servers WHERE #=feeders.name[ 'serverlist' ].id;", 0 ) ) { trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", sqltext(0) ) ); sqldone(); } } else if( Q_stricmp( name, "Quit" ) == 0 ) { trap_Cmd_ExecuteText( EXEC_NOW, "quit" ); } else if( Q_stricmp( name, "Leave" ) == 0 ) { if ( trap_Cvar_VariableInt("sv_running") == 0) { trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); } else { trap_Cmd_ExecuteText( EXEC_APPEND, "killserver\n"); } Menus_CloseAll(); } else if( Q_stricmp( name, "glCustom" ) == 0 ) { trap_Cvar_Set( "ui_glCustom", "4" ); } else if( Q_stricmp( name, "update" ) == 0 ) { if( String_Parse( args, &name2 ) ) UI_Update( name2 ); } else if( Q_stricmp( name, "setPbClStatus" ) == 0 ) { int stat; if ( Int_Parse( args, &stat ) ) trap_SetPbClStatus( stat ); } else if ( Q_stricmp( name, "gethighscores") == 0 ) { UI_ST_exec( UI_ST_REQUEST_HIGHSCORES ); } else if( Q_stricmp( name, "login" ) == 0 ) { UI_Login(); } else if( Q_stricmp( name, "closebugreport" ) == 0 ) { trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_BUG ); } else if ( Q_stricmp( name, "registergame" ) == 0 ) { trap_Cmd_ExecuteText( EXEC_APPEND, va("register %s\n", UI_Cvar_VariableString( "ui_licensekey" ) ) ); } else if ( Q_stricmp( name, "checkupdates" ) == 0 ) { trap_Cvar_Set( "com_changelog", "Space Trader is up to date." ); trap_Cvar_Set( "com_downloadbar_x", COM_Parse( args ) ); trap_Cvar_Set( "com_downloadbar_y", COM_Parse( args ) ); trap_Cvar_Set( "com_downloadbar_w", COM_Parse( args ) ); trap_Cvar_Set( "com_downloadbar_h", COM_Parse( args ) ); trap_Cmd_ExecuteText( EXEC_APPEND, "check_updates" ); } #ifdef DEVELOPER else if ( Q_stricmp( name, "editorupdate" ) == 0 ) { UI_Editor_UpdateItem(); } #endif else { Com_Printf( "unknown UI script %s\n", name ); } } } qboolean UI_hasSkinForBase(const char *base, const char *team) { char test[1024]; Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team ); if (trap_FS_FOpenFile(test, 0, FS_READ)) { return qtrue; } Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team ); if (trap_FS_FOpenFile(test, 0, FS_READ)) { return qtrue; } return qfalse; } static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) { return trap_CIN_PlayCinematic( name, (int)x, (int)y, (int)w, (int)h, (CIN_loop | CIN_silent) ); } static void UI_StopCinematic(int handle) { if ( handle >= 0 ) { trap_CIN_StopCinematic(handle); } } static void UI_DrawCinematic( int handle, float x, float y, float w, float h ) { trap_CIN_SetExtents( handle, (int)x, (int)y, (int)w, (int)h ); trap_CIN_DrawCinematic(handle); } static void UI_RunCinematicFrame( int handle ) { trap_CIN_RunCinematic( handle ); } void UI_Cvar_Set( const char* cvar, const char* value ) { trap_Cvar_Set( cvar, value ); } /* ================= UI_Init ================= */ void _UI_Init( qboolean inGameLoad ) { int start; //uiInfo.inGameLoad = inGameLoad; UI_RegisterCvars(); UI_InitMemory(); UI_Effect_Init(); // cache redundant calulations trap_GetGlconfig( &uiInfo.uiDC.glconfig ); //UI_Load(); uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip; uiInfo.uiDC.setColor = &trap_R_SetColor; uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic; uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic; uiInfo.uiDC.registerModel = &trap_R_RegisterModel; uiInfo.uiDC.modelBounds = &trap_R_ModelBounds; uiInfo.uiDC.fillRect = &trap_R_RenderRoundRect; uiInfo.uiDC.drawRect = &_UI_DrawRect; uiInfo.uiDC.drawSides = &_UI_DrawSides; uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom; uiInfo.uiDC.clearScene = &trap_R_ClearScene; uiInfo.uiDC.drawSides = &_UI_DrawSides; uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene; uiInfo.uiDC.renderScene = &trap_R_RenderScene; uiInfo.uiDC.registerFont = &trap_R_RegisterFont; uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw; uiInfo.uiDC.runScript = &UI_RunMenuScript; uiInfo.uiDC.setCVar = UI_Cvar_Set; uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer; uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue; uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode; uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode; uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound; uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey; uiInfo.uiDC.ownerDrawHandleMouseMove = &UI_OwnerDrawHandleMouseMove; uiInfo.uiDC.setBinding = &trap_Key_SetBinding; uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf; uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf; uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText; uiInfo.uiDC.Error = &Com_Error; uiInfo.uiDC.Print = &Com_Printf; uiInfo.uiDC.registerSound = &trap_S_RegisterSound; uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack; uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack; uiInfo.uiDC.playCinematic = &UI_PlayCinematic; uiInfo.uiDC.stopCinematic = &UI_StopCinematic; uiInfo.uiDC.drawCinematic = &UI_DrawCinematic; uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame; uiInfo.uiDC.getOwnerText = &UI_GetOwnerText; uiInfo.uiDC.getClientNum = &trap_GetClientNum; uiInfo.uiDC.toolTip = &UI_Effects_UpdateToolTip; Init_Display(&uiInfo.uiDC); memset( &ui_menuStack, 0, sizeof(ui_menuStack) ); String_Init(); uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "*white" ); AssetCache(); start = trap_Milliseconds(); uiInfo.traveltime = 0; uiInfo.maxplayers = 8; { char tmp[ MAX_INFO_STRING ]; trap_GetConfigString( CS_SERVERINFO, tmp, sizeof(tmp) ); uiInfo.maxplayers = atoi( Info_ValueForKey( tmp, "sv_maxplayers" ) ); } trap_SQL_Exec( "CREATE TABLE feeders" "(" "name STRING, " "sel INTEGER, " "id INTEGER, " "enabled INTEGER " ");" "CREATE TABLE sliders" "(" "name STRING, " "value INTEGER " ");" "CREATE TABLE IF NOT EXISTS strings" "(" "index INTEGER, " "name STRING " ");" "CREATE TABLE ui" "(" "key STRING, " "value INTEGER " ");" ); #ifdef USE_DRM trap_PC_AddGlobalDefine( "USE_DRM" ); #endif #ifdef DEMO trap_PC_AddGlobalDefine( "DEMO" ); #endif // check to see if 'cl_lang' is valid, default to english. if ( sql( "SELECT 1 FROM common.files SEARCH fullname 'ui/strings_'||$1||'.txt';", "t", UI_Cvar_VariableString("cl_lang") ) ) { sqldone(); } else { UI_Cvar_Set( "cl_lang", "en-US" ); } trap_PC_AddGlobalDefine( va("LANG \"%s\"",UI_Cvar_VariableString("cl_lang")) ); { char tmp[ 64 ]; trap_SQL_Run( tmp, sizeof(tmp), 0, 0,0,0 ); if ( tmp[ 0 ] == '\0' ) { trap_SQL_Compile( "1" ); UI_ParseStrings( va("ui/strings_%s.txt",UI_Cvar_VariableString("cl_lang")) ); } } if ( inGameLoad ) UI_LoadMenus( "ui/ingame.txt", qtrue ); else UI_LoadMenus( "ui/menus.txt", qtrue); uiInfo.tooltipDef1 = UI_Effect_Find( "tooltip1" ); uiInfo.tooltipDef2 = UI_Effect_Find( "tooltip2" ); #ifdef DEVELOPER UI_Editor_Init(); #endif Menus_CloseAll(); // initialize rules engine if ( !inGameLoad ) UI_ST_exec( UI_ST_INIT_FRONTEND ); UI_LoadBots(); // sets defaults for ui temp cvars uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair"); trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1"); uiInfo.serverStatus.currentServerCinematic = -1; trap_Cvar_Register(NULL, "debug_protocol", "", 0 ); uiInfo.missionStatus = 0; // the mission is in progress sql( "SELECT index FROM strings SEARCH name $;", "tsId", "T_Yes", &uiInfo.T_Yes ); sql( "SELECT index FROM strings SEARCH name $;", "tsId", "T_No", &uiInfo.T_No ); trap_Key_SetCatcher( 0 ); } /* ================= UI_KeyEvent ================= */ void _UI_KeyEvent( int key, qboolean down ) { Display_HandleKey( key, down, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory ); if ( !Menu_GetFocused() ) { trap_Key_ClearStates(); trap_Cvar_Set( "cl_paused", "0" ); } } /* ================= UI_MouseEvent ================= */ int _UI_MouseEvent( int dx, int dy ) { UI_AdjustTo640( &dx, &dy ); // update mouse screen position uiInfo.uiDC.cursorx = dx; uiInfo.uiDC.cursory = dy; return Display_MouseMove( uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory ); } void _UI_SetActiveMenu( uiMenuCommand_t menu ) { char buf[256]; // this should be the ONLY way the menu system is brought up // enusure minumum menu data is cached if( Menu_Count() > 0 ) { vec3_t v; v[0] = v[1] = v[2] = 0; switch( menu ) { case UIMENU_NONE: trap_Key_ClearStates(); trap_Cvar_Set( "cl_paused", "0" ); Menus_CloseAll(); return; case UIMENU_MAIN: UI_SetMenuStack( &cg_menuStack ); Menus_CloseAll(); UI_SetMenuStack( &ui_menuStack ); Menus_CloseAll(); if ( !GS_INPLAY && trap_Cvar_VariableInt( "com_downloading" ) == 1 ) { Menus_ActivateByName( "downloading" ); } else { Menus_ActivateByName( "welcome" ); UI_ST_exec( UI_ST_MAINMENU ); } trap_Cvar_VariableStringBuffer( "com_errorMessage", buf, sizeof( buf ) ); if( strlen( buf ) ) { if( Q_stricmp( "Disconnected from server", buf ) == 0 ) { trap_Cvar_Set( "com_errorMessage", "" ); } else { trap_Cvar_Set( "ui_errorMessage", buf ); Menus_ActivateByName( "error_popmenu" ); } } return; case UIMENU_TEAM: Menus_ActivateByName("team"); return; case UIMENU_NEED_CD: Menus_ActivateByName( "header" ); Menus_ActivateByName( "registergame" ); return; case UIMENU_BAD_CD_KEY: return; case UIMENU_INGAME: UI_ST_exec( UI_ST_INGAMEMENU ); return; case UIMENU_CHAT: UI_ST_exec( UI_ST_CHATMENU ); return; } } } qboolean _UI_IsFullscreen( void ) { return Menus_AnyFullScreenVisible(); } /* ======================== UI_DrawConnectScreen This will also be overlaid on the cgame info screen during loading to prevent it from blinking away too rapidly on local or lan games. ======================== */ void UI_DrawConnectScreen( qboolean overlay ) { char text[ MAX_INFO_STRING ]; uiClientState_t cstate; rectDef_t r; REF_PARAM( overlay ); // // see what information we should display // trap_GetClientState( &cstate ); text[0] = '\0'; if (!Q_stricmp(cstate.servername,"localhost")) { Q_strcat( text, sizeof(text), "Loading...\n" ); } else { Q_strcat( text, sizeof(text), va("Connecting to %s\n", cstate.servername)); switch ( cstate.connState ) { case CA_CONNECTING: Q_strcat( text, sizeof(text), va("Awaiting connection...%i\n", cstate.connectPacketCount) ); break; case CA_CHALLENGING: Q_strcat( text, sizeof(text), va("Awaiting challenge...%i\n", cstate.connectPacketCount) ); break; case CA_CONNECTED: Q_strcat( text, sizeof(text), "Awaiting gamestate...\n" ); break; case CA_UNINITIALIZED: case CA_DISCONNECTED: case CA_AUTHORIZING: case CA_LOADING: case CA_PRIMED: case CA_ACTIVE: case CA_CINEMATIC: break; } } r.x = 50.0f; r.y = 0.0f; r.w = 540.0f; r.h = 450.0f; trap_R_RenderText ( &r, 0.35f, colorWhite, text, sizeof(text), TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT, ITEM_TEXTSTYLE_SHADOWED | ITEM_TEXTSTYLE_ITALIC, uiInfo.uiDC.Assets.font, -1, 0 ); // password required / connection rejected information goes here } /* ================ cvars ================ */ typedef struct { vmCvar_t *vmCvar; char *cvarName; char *defaultString; int cvarFlags; } cvarTable_t; vmCvar_t ui_botsFile; vmCvar_t ui_brassTime; vmCvar_t ui_drawCrosshair; vmCvar_t ui_drawCrosshairNames; vmCvar_t ui_marks; vmCvar_t ui_gameType; vmCvar_t ui_netSource; vmCvar_t ui_serverFilterType; vmCvar_t ui_currentMap; vmCvar_t ui_currentNetMap; vmCvar_t ui_singlePlayerActive; vmCvar_t ui_username; vmCvar_t ui_password; vmCvar_t ui_crosshairColorR; vmCvar_t ui_crosshairColorG; vmCvar_t ui_crosshairColorB; vmCvar_t ui_crosshairColorA; vmCvar_t cl_cornersize; // bk001129 - made static to avoid aliasing static cvarTable_t cvarTable[] = { { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM }, { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE }, { &ui_drawCrosshair, "cg_drawCrosshair", "2", CVAR_ARCHIVE }, { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE }, { &ui_new, "ui_new", "0", CVAR_TEMP }, { &ui_debug, "ui_debug", "0", CVAR_TEMP }, { &ui_initialized, "ui_initialized", "0", CVAR_TEMP }, { &ui_spacetrader, "cl_spacetrader", "0", CVAR_TEMP }, { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE }, { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE }, { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE }, { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0}, { &ui_tooltipmode, "ui_tooltipmode", "0", CVAR_ARCHIVE}, { &ui_drawMenu, "ui_drawMenu", "1", CVAR_TEMP }, { &ui_username, "ui_username", "", CVAR_ARCHIVE}, { &ui_password, "ui_password", "", CVAR_ARCHIVE}, { &ui_crosshairColorR, "cg_crosshairColorR", "1.0", CVAR_ARCHIVE}, { &ui_crosshairColorG, "cg_crosshairColorG", "1.0", CVAR_ARCHIVE}, { &ui_crosshairColorB, "cg_crosshairColorB", "1.0", CVAR_ARCHIVE}, { &ui_crosshairColorA, "cg_crosshairColorA", "1.0", CVAR_ARCHIVE}, { &cl_cornersize, "cl_cornersize", "", 0}, }; // bk001129 - made static to avoid aliasing static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]); /* ================= UI_RegisterCvars ================= */ void UI_RegisterCvars( void ) { int i; cvarTable_t *cv; for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) { trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags ); } } /* ================= UI_UpdateCvars ================= */ void UI_UpdateCvars( void ) { int i; cvarTable_t *cv; for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) { trap_Cvar_Update( cv->vmCvar ); } } /* ================= ArenaServers_StopRefresh ================= */ static void UI_StopServerRefresh( void ) { if (!uiInfo.serverStatus.refreshActive) { // not currently refreshing return; } uiInfo.serverStatus.refreshActive = qfalse; } /* ================= UI_DoServerRefresh ================= */ static void UI_DoServerRefresh( void ) { if (!uiInfo.serverStatus.refreshActive) { return; } if (uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh ) { UI_StartServerRefresh(); return; } if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) { return; } // if still trying to retrieve pings if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) { uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000; } } /* ================= UI_StartServerRefresh ================= */ static void UI_StartServerRefresh() { qtime_t q; int delay; trap_RealTime(&q); 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)); // if( ui_netSource.integer == AS_LOCAL ) { // clear number of displayed servers sql( "DELETE FROM servers WHERE lastupdate < ?1;", "ie", uiInfo.uiDC.realTime-2000 ); trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" ); uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000; delay = 2500; } else { // clear number of displayed servers //sql( "DELETE FROM servers WHERE lastupdate < ?1;", "ie", uiInfo.uiDC.realTime-10000 ); uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000; if( ui_netSource.integer == AS_GLOBAL ) { trap_Cmd_ExecuteText( EXEC_NOW, "getservers" ); } delay = 10000; } uiInfo.serverStatus.refreshActive = qtrue; uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + delay; } void UI_Effects_UpdateToolTip( itemDef_t * item ) { item; #if 0 effectDef_t * e; // kill old tooltip if ( uiInfo.tooltip ) UI_Effect_SetFlag( uiInfo.tooltip, EF_NOFOCUS ); if ( ui_tooltipmode.integer == 0 ) return; e = (ui_tooltipmode.integer==2)?uiInfo.tooltipDef2:uiInfo.tooltipDef1; if ( item && item->tooltip && e ) { char t[ EFFECT_TEXT_LENGTH ]; rectDef_t r; r.x = e->rect.x + (float)uiInfo.uiDC.cursorx; r.y = e->rect.x + (float)uiInfo.uiDC.cursory; r.w = e->rect.w; r.h = e->rect.h; trap_SQL_Run( t, sizeof(t), item->tooltip, 0,0,0 ); uiInfo.tooltip = UI_Effect_SpawnText( 0, e, t, 0 ); UI_Effect_SetRect( uiInfo.tooltip, &r, item ); } #endif }