/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { if ( cg_showmiss.integer ) { CG_Printf( "CG_MapRestart\n" ); } CG_InitLocalEntities(); CG_InitMarkPolys(); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime = 0; cg.mapRestart = qtrue; CG_StartMusic(); trap_S_ClearLoopingSounds(qtrue); // we really should clear more parts of cg here and stop sounds #ifdef MISSIONPACK if (cg_singlePlayerActive.integer) { trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time)); if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) { trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string)); } } #endif }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { if( cg_showmiss.integer ) CG_Printf( "CG_MapRestart\n" ); CG_InitMarkPolys( ); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime[ TEAM_NONE ] = 0; cg.mapRestart = qtrue; CG_StartMusic( ); trap_S_ClearLoopingSounds( qtrue ); // we really should clear more parts of cg here and stop sounds trap_Cvar_Set( "cg_thirdPerson", "0" ); cg.splashTime = cg.time; }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { if ( cg_showmiss.integer ) { CG_Printf( "CG_MapRestart\n" ); } CG_InitMarkPolys(); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime = 0; cg.mapRestart = qtrue; CG_StartMusic(); trap_S_ClearLoopingSounds( qtrue ); // we really should clear more parts of cg here and stop sounds // play the "fight" sound if this is a restart without warmup if ( cg.warmup == 0 ) { CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH * 2 ); } trap_Cvar_Set( "cg_thirdPerson", "0" ); }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart(void) { if(cg_showmiss.integer) { CG_Printf("CG_MapRestart\n"); } CG_InitLocalEntities(); CG_InitMarkPolys(); CG_InitParticles(); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime = 0; cg.mapRestart = qtrue; CG_StartMusic(); trap_S_ClearLoopingSounds(qtrue); // we really should clear more parts of cg here and stop sounds // play the "fight" sound if this is a restart without warmup if(cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */ ) { trap_S_StartLocalSound(cgs.media.countFightSound, CHAN_ANNOUNCER); CG_CenterPrint("FIGHT!", 120, GIANTCHAR_WIDTH * 2); } #ifdef MISSIONPACK if(cg_singlePlayerActive.integer) { trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time)); if(cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) { trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string)); } } #endif trap_Cvar_Set("cg_cameraOrbit", "0"); trap_Cvar_Set("cg_thirdPerson", "0"); }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { if ( cg_showmiss.integer ) { CG_Printf( "CG_MapRestart\n" ); } trap_R_ClearDecals ( ); //FIXME: trap_FX_Reset? CG_InitLocalEntities(); CG_InitMarkPolys(); CG_ClearParticles (); CG_KillCEntityInstances(); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime = 0; cg.mapRestart = qtrue; CG_StartMusic(qtrue); trap_S_ClearLoopingSounds(); // we really should clear more parts of cg here and stop sounds // play the "fight" sound if this is a restart without warmup if ( cg.warmup == 0 && cgs.gametype != GT_SIEGE && cgs.gametype != GT_POWERDUEL/* && cgs.gametype == GT_DUEL */) { trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); CG_CenterPrint( CG_GetStringEdString("MP_SVGAME", "BEGIN_DUEL"), 120, GIANTCHAR_WIDTH*2 ); } /* if (cg_singlePlayerActive.integer) { trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time)); if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) { trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string)); } } */ trap_Cvar_Set("cg_thirdPerson", "0"); }
/** The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournament restart will clear everything, but doesn't require a reload of all the media */ static void CG_MapRestart(void) { if (cg_showmiss.integer) { CG_Printf("CG_MapRestart\n"); } CG_InitLocalEntities(); CG_InitMarkPolys(); CG_ClearParticles(); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.rewardTime = 0; cg.rewardStack = 0; cg.intermissionStarted = qfalse; cg.levelShot = qfalse; memset(&cg.statsOwn, 0, sizeof cg.statsOwn); memset(&cg.statsFollow, 0, sizeof cg.statsFollow); memset(&cg.statsEnemy, 0, sizeof cg.statsEnemy); cgs.voteTime = 0; cg.mapRestart = qtrue; trap_S_ClearLoopingSounds(qtrue); // we really should clear more parts of cg here and stop sounds // play the "fight" sound if this is a restart without warmup if (cgs.warmup == 0) { trap_S_StartLocalSound(cgs.media.countFightSound, CHAN_ANNOUNCER); CG_CenterPrint("Fight!"); } trap_Cvar_Set("cg_thirdPerson", "0"); }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { if ( cg_showmiss.integer ) { CG_Printf( "CG_MapRestart\n" ); } CG_InitMarkPolys(); cg.intermissionStarted = qfalse; cgs.voteTime[ TEAM_NONE ] = 0; cg.mapRestart = qtrue; CG_StartMusic(); trap_S_ClearLoopingSounds( qtrue ); // we really should clear more parts of cg here and stop sounds trap_Cvar_Set( "cg_thirdPerson", "0" ); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars( ); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if( cg.infoScreenText[ 0 ] != 0 ) { CG_DrawLoadingScreen( ); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds( qfalse ); // clear all the render lists trap_R_ClearScene( ); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots( ); // if we haven't received any snapshots yet, all // we can draw is the information screen if( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawLoadingScreen( ); return; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity ); // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState( ); // decide on third person view cg.renderingThirdPerson = ( cg_thirdPerson.integer || ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) || ( cg.chaseFollow && cg.snap->ps.pm_flags & PMF_FOLLOW) ); // update speedometer CG_AddSpeed( ); // build cg.refdef inwater = CG_CalcViewValues( ); // build the render lists if( !cg.hyperspace ) { CG_AddPacketEntities( ); // after calcViewValues, so predicted player state is correct CG_AddMarks( ); } CG_AddViewWeapon( &cg.predictedPlayerState ); //after CG_AddViewWeapon if( !cg.hyperspace ) { CG_AddParticles( ); CG_AddTrails( ); } // add buffered sounds CG_PlayBufferedSounds( ); // finish up the rest of the refdef if( cg.testModelEntity.hModel ) CG_AddTestModel( ); cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); //remove expired console lines if( cg.consoleLines[ 0 ].time + cg_consoleLatency.integer < cg.time && cg_consoleLatency.integer > 0 ) CG_RemoveNotifyLine( ); // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; if( cg.frametime < 0 ) cg.frametime = 0; cg.oldTime = cg.time; CG_AddLagometerFrameInfo( ); } if( cg_timescale.value != cg_timescaleFadeEnd.value ) { if( cg_timescale.value < cg_timescaleFadeEnd.value ) { cg_timescale.value += cg_timescaleFadeSpeed.value * ( (float)cg.frametime ) / 1000; if( cg_timescale.value > cg_timescaleFadeEnd.value ) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ( (float)cg.frametime ) / 1000; if( cg_timescale.value < cg_timescaleFadeEnd.value ) cg_timescale.value = cg_timescaleFadeEnd.value; } if( cg_timescaleFadeSpeed.value ) trap_Cvar_Set( "timescale", va( "%f", cg_timescale.value ) ); } // actually issue the rendering calls CG_DrawActive( stereoView ); if( cg_stats.integer ) CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; cg.cld = 0; // NERVE - SMF - reset clientDamage #ifdef DEBUGTIME_ENABLED int dbgTime = trap_Milliseconds(),elapsed; int dbgCnt = 0; #endif cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); /* // RF, if we should force a weapon, then do so if( !cg.weaponSelect ) { if (cg_loadWeaponSelect.integer > 0) { cg.weaponSelect = cg_loadWeaponSelect.integer; cg.weaponSelectTime = cg.time; trap_Cvar_Set( "cg_loadWeaponSelect", "0" ); // turn it off } } */ #ifdef DEBUGTIME_ENABLED CG_Printf( "\n" ); #endif DEBUGTIME // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds( qfalse ); DEBUGTIME // clear all the render lists trap_R_ClearScene(); DEBUGTIME // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); DEBUGTIME // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } if ( cg.weaponSelect == WP_FG42SCOPE || cg.weaponSelect == WP_SNOOPERSCOPE || cg.weaponSelect == WP_SNIPERRIFLE ) { float spd; spd = VectorLength( cg.snap->ps.velocity ); if ( spd > 180.0f ) { switch ( cg.weaponSelect ) { case WP_FG42SCOPE: CG_FinishWeaponChange( cg.weaponSelect, WP_FG42 ); break; case WP_SNOOPERSCOPE: CG_FinishWeaponChange( cg.weaponSelect, WP_GARAND ); break; case WP_SNIPERRIFLE: CG_FinishWeaponChange( cg.weaponSelect, WP_MAUSER ); break; } } } DEBUGTIME if ( !cg.lightstylesInited ) { CG_SetupDlightstyles(); } DEBUGTIME // if we have been told not to render, don't if ( cg_norender.integer ) { return; } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); DEBUGTIME // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer /*|| (cg.snap->ps.stats[STAT_HEALTH] <= 0)*/; // build cg.refdef inwater = CG_CalcViewValues(); CG_CalcShakeCamera(); CG_ApplyShakeCamera(); DEBUGTIME // RF, draw the skyboxportal CG_DrawSkyBoxPortal(); DEBUGTIME if ( inwater ) { CG_UnderwaterSounds(); } DEBUGTIME // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } DEBUGTIME // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); DEBUGTIME // Rafael particles CG_AddParticles(); // done. DEBUGTIME CG_AddLocalEntities(); DEBUGTIME }
/* ================= CG_Init Called after every level change or subsystem restart Will perform callbacks to make the loading info screen update. ================= */ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { const char *s; // clear everything memset( &cgs, 0, sizeof( cgs ) ); memset( &cg, 0, sizeof( cg ) ); memset( cg_entities, 0, sizeof(cg_entities) ); memset( cg_weapons, 0, sizeof(cg_weapons) ); cg.clientNum = clientNum; cgs.processedSnapshotNum = serverMessageNum; cgs.serverCommandSequence = serverCommandSequence; // load a few needed things before we do any screen updates cgs.media.charsetShader = trap_R_RegisterShader( "interface/fonts/font0.png" ); cgs.media.whiteShader = trap_R_RegisterShader( "white" ); cgs.media.clearShader = trap_R_RegisterShader( "clear" ); cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "interface/fonts/font1.png" ); cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "interface/fonts/font1Glow.png" ); cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "interface/fonts/font2.png" ); CG_RegisterCvars(); CG_InitConsoleCommands(); cg.weaponSelect = 1; // get the rendering configuration from the client system trap_GetGlconfig( &cgs.glconfig ); cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; // get the gamestate from the client system trap_GetGameState( &cgs.gameState ); // check version s = CG_ConfigString( CS_PRODUCT_VERSION ); if ( strcmp( s, PRODUCT_VERSION ) ) { CG_Error( "Client/Server game mismatch: %s/%s", PRODUCT_VERSION, s ); } s = CG_ConfigString( CS_LEVEL_START_TIME ); cgs.levelStartTime = atoi( s ); CG_ParseServerinfo(); // load the new map CG_LoadingString( "collision map" ); trap_CM_LoadMap( cgs.mapname ); cg.loading = qtrue; // force players to load instead of defer CG_LoadingString( "sounds" ); CG_RegisterSounds(); CG_LoadingString( "graphics" ); CG_RegisterGraphics(); CG_LoadingString( "clients" ); CG_RegisterClients(); // if low on memory, some clients will be deferred cg.loading = qfalse; // future players will be deferred CG_InitLocalEntities(); // ADDING FOR ZEQ2 CG_FrameHist_Init(); CG_InitTrails(); CG_InitParticleSystems(); CG_InitBeamTables(); CG_InitRadarBlips(); // END ADDING CG_InitMarkPolys(); // remove the last loading update cg.infoScreenText[0] = 0; // Make sure we have update values (scores) CG_SetConfigValues(); CG_LoadingString( "" ); CG_ShaderStateChanged(); trap_S_ClearLoopingSounds( qtrue ); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; int mpSetup; // NERVE - SMF #ifdef DEBUGTIME_ENABLED int dbgTime=trap_Milliseconds(),elapsed; int dbgCnt=0; #endif cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); #ifdef DEBUGTIME_ENABLED CG_Printf("\n"); #endif DEBUGTIME // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); DEBUGTIME // clear all the render lists trap_R_ClearScene(); DEBUGTIME // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); DEBUGTIME // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } // check for server set weapons we might not know about // (FIXME: this is a hack for the time being since a scripted "selectweapon" does // not hit the first snap, the server weapon set in cg_playerstate.c line 219 doesn't // do the trick) if( !cg.weaponSelect && cg.snap->ps.weapon) { cg.weaponSelect = cg.snap->ps.weapon; cg.weaponSelectTime = cg.time; } //----(SA) nerve uses this for snooper/sniper if (cg.weaponSelect == WP_FG42SCOPE) { float spd; spd = VectorLength(cg.snap->ps.velocity); if (spd > 180.0f) CG_FinishWeaponChange(WP_FG42SCOPE, WP_FG42); } DEBUGTIME if(!cg.lightstylesInited) CG_SetupDlightstyles(); DEBUGTIME // if we have been told not to render, don't if (cg_norender.integer) { return; } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); DEBUGTIME // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); // build cg.refdef inwater = CG_CalcViewValues(); DEBUGTIME // RF, draw the skyboxportal CG_DrawSkyBoxPortal(); DEBUGTIME if(inwater) CG_UnderwaterSounds(); DEBUGTIME // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } DEBUGTIME // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); DEBUGTIME // Rafael particles CG_AddParticles (); // done. DEBUGTIME CG_AddLocalEntities(); DEBUGTIME }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { // loadingscreen #ifdef SCRIPTHUD CG_DrawLoadingScreen( ); #else CG_DrawInformation(); #endif // end loadingscreen return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { // loadingscreen #ifdef SCRIPTHUD CG_DrawLoadingScreen( ); #else CG_DrawInformation(); #endif // end loadingscreen return; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity ); // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); // decide on third person view if (!cg_deathcam.integer) // leilei - allow first person deathcam cg.renderingThirdPerson = cg_thirdPerson.integer; else cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); // build cg.refdef inwater = CG_CalcViewValues(); // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddLocalEntities(); } CG_AddViewWeapon( &cg.predictedPlayerState ); // add buffered sounds CG_PlayBufferedSounds(); // play buffered voice chats CG_PlayBufferedVoiceChats(); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; if ( cg.frametime < 0 ) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive( stereoView ); if ( cg_stats.integer ) { CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } }
/* ================= CG_Init Called after every level change or subsystem restart Will perform callbacks to make the loading info screen update. ================= */ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { const char *s; // clear everything memset( &cgs, 0, sizeof( cgs ) ); memset( &cg, 0, sizeof( cg ) ); memset( cg_entities, 0, sizeof(cg_entities) ); memset( cg_weapons, 0, sizeof(cg_weapons) ); memset( cg_items, 0, sizeof(cg_items) ); cg.clientNum = clientNum; cgs.processedSnapshotNum = serverMessageNum; cgs.serverCommandSequence = serverCommandSequence; // load a few needed things before we do any screen updates cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" ); cgs.media.whiteShader = trap_R_RegisterShader( "white" ); cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" ); cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" ); CG_RegisterCvars(); CG_InitConsoleCommands(); cg.weaponSelect = WP_MACHINEGUN; cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for cgs.flagStatus = -1; // old servers // get the rendering configuration from the client system trap_GetGlconfig( &cgs.glconfig ); cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; // get the gamestate from the client system trap_GetGameState( &cgs.gameState ); // check version s = CG_ConfigString( CS_GAME_VERSION ); if ( strcmp( s, GAME_VERSION ) ) { CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); } s = CG_ConfigString( CS_LEVEL_START_TIME ); cgs.levelStartTime = atoi( s ); CG_ParseServerinfo(); // load the new map CG_LoadingString( "collision map" ); trap_CM_LoadMap( cgs.mapname ); cg.loading = qtrue; // force players to load instead of defer CG_LoadingString( "sounds" ); CG_RegisterSounds(); CG_LoadingString( "graphics" ); CG_RegisterGraphics(); CG_LoadingString( "clients" ); CG_RegisterClients(); // if low on memory, some clients will be deferred cg.loading = qfalse; // future players will be deferred CG_InitLocalEntities(); CG_InitMarkPolys(); // remove the last loading update cg.infoScreenText[0] = 0; // Make sure we have update values (scores) CG_SetConfigValues(); CG_StartMusic(); CG_LoadingString( "" ); CG_ShaderStateChanged(); trap_S_ClearLoopingSounds( qtrue ); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; qboolean renderClientViewport[MAX_SPLITVIEW]; int i; cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // Use single camera/viewport at intermission for (i = 0; i < CG_MaxSplitView(); i++) { if (cg.snap->lcIndex[i] != -1 && cg.snap->pss[i].pm_type != PM_INTERMISSION) { // client present and not at intermission, keep viewports separate. break; } } cg.singleCamera = (cg.snap->numPSs > 1) && (i == CG_MaxSplitView()); cg.numViewports = 0; for (i = 0; i < CG_MaxSplitView(); i++) { if (cg.snap->lcIndex[i] == -1) { renderClientViewport[i] = qfalse; continue; } cg.cur_localClientNum = i; cg.cur_lc = &cg.localClients[i]; cg.cur_ps = &cg.snap->pss[cg.snap->lcIndex[i]]; // Check if viewport should be drawn. if ( cg.singleCamera && cg.numViewports >= 1 ) { renderClientViewport[i] = qfalse; } else { cg.numViewports++; renderClientViewport[i] = qtrue; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue( cg.cur_lc->weaponSelect, cg.cur_lc->zoomSensitivity, cg.cur_localClientNum ); // update cg.predictedPlayerState CG_PredictPlayerState(); // Remove expired console lines if( cg.cur_lc->consoleLines[ 0 ].time + cg_consoleLatency.integer < cg.time && cg_consoleLatency.integer > 0 ) { CG_RemoveNotifyLine( cg.cur_lc ); } } // If all local clients dropped out from playing still draw main local client. if (cg.numViewports == 0) { cg.numViewports = 1; renderClientViewport[0] = qtrue; } // play lead change annoucement and time/frag limit warnings CG_CheckGameSounds(); // add buffered sounds CG_PlayBufferedSounds(); #ifdef MISSIONPACK // play buffered voice chats CG_PlayBufferedVoiceChats(); #endif for (i = 0, cg.viewport = -1; i < CG_MaxSplitView(); i++) { if (!renderClientViewport[i]) { continue; } cg.viewport++; cg.cur_localClientNum = i; cg.cur_lc = &cg.localClients[i]; cg.cur_ps = &cg.snap->pss[cg.snap->lcIndex[i]]; // decide on third person view cg.cur_lc->renderingThirdPerson = cg_thirdPerson[cg.cur_localClientNum].integer || (cg.cur_ps->stats[STAT_HEALTH] <= 0); CG_PB_ClearPolyBuffers(); // build cg.refdef inwater = CG_CalcViewValues(); CG_SetupFrustum(); // first person blend blobs, done after AnglesToAxis if ( !cg.cur_lc->renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.cur_lc->hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddParticles (); CG_AddLocalEntities(); CG_AddAtmosphericEffects(); } CG_AddViewWeapon( &cg.cur_lc->predictedPlayerState ); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // update audio positions trap_S_Respatialize( cg.cur_ps->clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater, !cg.cur_lc->renderingThirdPerson ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT && cg.viewport == 0 ) { cg.frametime = cg.time - cg.oldTime; if ( cg.frametime < 0 ) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive( stereoView ); } // load any models that have been deferred if a scoreboard is shown if ( !CG_AnyScoreboardShowing() ) { cg.deferredPlayerLoading = 0; } else if ( ++cg.deferredPlayerLoading > 10 ) { CG_LoadDeferredPlayers(); } if (cg.numViewports != 1) { // Setup single viewport cg.numViewports = 1; cg.viewport = 0; // calculate size of viewport CG_CalcVrect(); } // Not drawing single client view. cg.cur_lc = NULL; cg.cur_ps = NULL; cg.cur_localClientNum = -1; // Draw over all viewports CG_DrawScreen2D( stereoView ); if ( cg_stats.integer ) { CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } }
/* ================= CG_Init Called after every level change or subsystem restart Will perform callbacks to make the loading info screen update. ================= */ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum, int randomSeed ) { const char *s; // clear everything memset( &cgs, 0, sizeof( cgs ) ); memset( &cg, 0, sizeof( cg ) ); memset( cg_entities, 0, sizeof(cg_entities) ); srand( randomSeed ); cg.clientNum = clientNum; cgs.processedSnapshotNum = serverMessageNum; cgs.serverCommandSequence = serverCommandSequence; trap_R_RegisterFont( "facfont-20", 0, &cgs.media.facfont ); trap_R_RegisterFont( "verdana-14", 0, &cgs.media.verdana ); // load a few needed things before we do any screen updates // cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" ); cgs.media.whiteShader = trap_R_RegisterShader( "*white" ); // cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" ); // cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); // cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" ); cgs.media.blackShader = trap_R_RegisterShaderNoMip( "textures/mohmenu/black.tga" ); CG_RegisterCvars(); CG_InitConsoleCommands(); // get the rendering configuration from the client system trap_GetGlconfig( &cgs.glconfig ); cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; // get the gamestate from the client system trap_GetGameState( &cgs.gameState ); // check version s = CG_ConfigString( CS_GAME_VERSION ); if ( strcmp( s, GAME_VERSION ) ) { CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); } s = CG_ConfigString( CS_LEVEL_START_TIME ); cgs.levelStartTime = atoi( s ); CG_ParseServerinfo(); // load the new map CG_LoadingString( "collision map" ); trap_CM_LoadMap( cgs.mapname ); CG_LoadingString( "sounds" ); CG_RegisterSounds(); CG_LoadUbersound(); CG_LoadingString( "graphics" ); CG_RegisterGraphics(); CG_LoadingString( "clients" ); CG_RegisterClients(); // if low on memory, some clients will be deferred CG_InitLocalEntities(); CG_InitMarkPolys(); CG_InitEventSystem(); CG_InitBeams(); CG_InitRainEffect(); // remove the last loading update cg.infoScreenText[0] = 0; // Make sure we have update values (scores) CG_SetConfigValues(); CG_StartMusic(); CG_LoadingString( "" ); trap_S_ClearLoopingSounds( qtrue ); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; cg.time = serverTime; cg.demoPlayback = demoPlayback; if (cg.snap && ui_myteam.integer != cg.snap->ps.persistant[PERS_TEAM]) { trap_Cvar_Set ( "ui_myteam", va("%i", cg.snap->ps.persistant[PERS_TEAM]) ); } // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } trap_FX_AdjustTime( cg.time, cg.refdef.vieworg, cg.refdef.viewaxis ); CG_RunLightStyles(); // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); trap_ROFF_UpdateEntities(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } // let the client system know what our weapon and zoom settings are if (cg.snap && cg.snap->ps.saberLockTime > cg.time) { trap_SetUserCmdValue( cg.weaponSelect, 0.01, cg.forceSelect, cg.itemSelect ); } else if (cg.snap && cg.snap->ps.usingATST) { trap_SetUserCmdValue( cg.weaponSelect, 0.2, cg.forceSelect, cg.itemSelect ); } else { trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity, cg.forceSelect, cg.itemSelect ); } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); if (cg.snap->ps.stats[STAT_HEALTH] > 0 && (cg.predictedPlayerState.weapon == WP_SABER || cg.predictedPlayerState.usingATST || cg.predictedPlayerState.forceHandExtend == HANDEXTEND_KNOCKDOWN || cg.predictedPlayerState.fallingToDeath)) { cg.renderingThirdPerson = 1; } else if (cg.snap->ps.zoomMode) { //always force first person when zoomed cg.renderingThirdPerson = 0; } // build cg.refdef inwater = CG_CalcViewValues(); CG_CalcScreenEffects(); // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddParticles (); CG_AddLocalEntities(); } CG_AddViewWeapon( &cg.predictedPlayerState ); if ( !cg.hyperspace) { trap_FX_AddScheduledEffects(); } // add buffered sounds CG_PlayBufferedSounds(); // play buffered voice chats CG_PlayBufferedVoiceChats(); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // if there are any entities flagged as sound trackers and attached to other entities, update their sound pos CG_UpdateSoundTrackers(); if (gCGHasFallVector) { vec3_t lookAng; VectorSubtract(cg.snap->ps.origin, cg.refdef.vieworg, lookAng); VectorNormalize(lookAng); vectoangles(lookAng, lookAng); VectorCopy(gCGFallVector, cg.refdef.vieworg); AnglesToAxis(lookAng, cg.refdef.viewaxis); } // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; if ( cg.frametime < 0 ) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive( stereoView ); if ( cg_stats.integer ) { CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } }
/* =============== CG_MapRestart The server has issued a map_restart, so the next snapshot is completely new and should not be interpolated to. A tournement restart will clear everything, but doesn't require a reload of all the media =============== */ static void CG_MapRestart( void ) { // char buff[64]; int i; if ( cg_showmiss.integer ) { CG_Printf( "CG_MapRestart\n" ); } memset( &cg.lastWeapSelInBank[0], 0, MAX_WEAP_BANKS * sizeof( int ) ); // clear weapon bank selections cg.centerPrintTime = 0; // reset centerprint counter so previous messages don't re-appear cg.itemPickupTime = 0; // reset item pickup counter so previous messages don't re-appear cg.cursorHintFade = 0; // reset cursor hint timer cg.yougotmailTime = 0; // reset // (SA) clear zoom (so no warpies) cg.zoomedBinoc = qfalse; cg.zoomedBinoc = cg.zoomedScope = qfalse; cg.zoomTime = 0; cg.zoomval = 0; // reset fog to world fog (if present) // trap_R_SetFog(FOG_CMD_SWITCHFOG, FOG_MAP,20,0,0,0,0); // trap_Cvar_VariableStringBuffer("r_mapFogColor", buff, sizeof(buff)); // trap_SendClientCommand(va("fogswitch %s", buff) ); CG_InitLocalEntities(); CG_InitMarkPolys(); //Rafael particles CG_ClearParticles(); // done. for ( i = 1; i < MAX_PARTICLES_AREAS; i++ ) { { int rval; rval = CG_NewParticleArea( CS_PARTICLES + i ); if ( !rval ) { break; } } } // Ridah, trails CG_ClearTrails(); // done. // Ridah CG_ClearFlameChunks(); CG_SoundInit(); // done. // RF, init ZombieFX trap_RB_ZombieFXAddNewHit( -1, NULL, NULL ); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; cgs.voteTime = 0; cg.lightstylesInited = qfalse; cg.mapRestart = qtrue; CG_StartMusic(); trap_S_ClearLoopingSounds( qtrue ); // we really should clear more parts of cg here and stop sounds cg.v_dmg_time = 0; cg.v_noFireTime = 0; cg.v_fireTime = 0; // RF, clear out animScriptData so we recalc everything and get new pointers from server memset( cgs.animScriptData.modelInfo, 0, sizeof( cgs.animScriptData.modelInfo ) ); for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( cgs.clientinfo[i].infoValid ) { CG_LoadClientInfo( &cgs.clientinfo[i] ); // re-register the valid clients } } // always clear the weapon selection cg.weaponSelect = WP_NONE; // clear out the player weapon info memset( &cg_entities[0].pe.weap, 0, sizeof( cg_entities[0].pe.weap ) ); // check for server set weapons we might not know about // (FIXME: this is a hack for the time being since a scripted "selectweapon" does // not hit the first snap, the server weapon set in cg_playerstate.c line 219 doesn't // do the trick) if ( !cg.weaponSelect ) { if ( cg_loadWeaponSelect.integer > 0 ) { cg.weaponSelect = cg_loadWeaponSelect.integer; cg.weaponSelectTime = cg.time; trap_Cvar_Set( "cg_loadWeaponSelect", "0" ); // turn it off } } // clear out rumble effects memset( cg.cameraShake, 0, sizeof( cg.cameraShake ) ); memset( cg.cameraShakeAngles, 0, sizeof( cg.cameraShakeAngles ) ); cg.rumbleScale = 0; // play the "fight" sound if this is a restart without warmup // if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) { // trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); // CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 ); // } #ifdef MISSIONPACK if ( cg_singlePlayerActive.integer ) { trap_Cvar_Set( "ui_matchStartTime", va( "%i", cg.time ) ); if ( cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string ) { trap_SendConsoleCommand( va( "set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string ) ); } } #endif trap_Cvar_Set( "cg_thirdPerson", "0" ); }
void CG_DemosDrawActiveFrame( int serverTime, stereoFrame_t stereoView ) { int deltaTime; qboolean hadSkip; qboolean captureFrame; float captureFPS; float frameSpeed; int blurTotal, blurIndex; float blurFraction; float stereoSep = CG_Cvar_Get( "r_stereoSeparation" ); int inwater, entityNum; if (!demo.initDone) { if ( !cg.snap ) { demoProcessSnapShots( qtrue ); } if ( !cg.snap ) { CG_Error( "No Initial demo snapshot found" ); } demoPlaybackInit(); } cg.demoPlayback = 2; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.loading ) { CG_DrawInformation(); return; } captureFrame = demo.capture.active && !demo.play.paused; if ( captureFrame ) { trap_MME_BlurInfo( &blurTotal, &blurIndex ); captureFPS = mov_captureFPS.value; if ( blurTotal > 0) { captureFPS *= blurTotal; blurFraction = blurIndex / (float)blurTotal; } else { blurFraction = 0; } } else { } /* Forward the demo */ deltaTime = serverTime - demo.serverTime; if (deltaTime > 50) deltaTime = 50; demo.serverTime = serverTime; demo.serverDeltaTime = 0.001 * deltaTime; cg.oldTime = cg.time; cg.oldTimeFraction = cg.timeFraction; if (demo.play.time < 0) { demo.play.time = demo.play.fraction = 0; } demo.play.oldTime = demo.play.time; /* Handle the music */ if ( demo.play.paused ) { if ( lastMusicStart >= 0) demoSynchMusic( -1, 0 ); } else { int musicStart = (demo.play.time - mov_musicStart.value * 1000 ); if ( musicStart <= 0 ) { if (lastMusicStart >= 0 ) demoSynchMusic( -1, 0 ); } else { if ( demo.play.time != demo.play.lastTime || lastMusicStart < 0) demoSynchMusic( musicStart, 0 ); } } /* forward the time a bit till the moment of capture */ if ( captureFrame && demo.capture.locked && demo.play.time < demo.capture.start ) { int left = demo.capture.start - demo.play.time; if ( left > 2000) { left -= 1000; captureFrame = qfalse; } else if (left > 5) { captureFrame = qfalse; left = 5; } demo.play.time += left; } else if ( captureFrame && demo.loop.total && blurTotal ) { float loopFraction = demo.loop.index / (float)demo.loop.total; demo.play.time = demo.loop.start; demo.play.fraction = demo.loop.range * loopFraction; demo.play.time += (int)demo.play.fraction; demo.play.fraction -= (int)demo.play.fraction; } else if (captureFrame) { float frameDelay = 1000.0f / captureFPS; demo.play.fraction += frameDelay * demo.play.speed; demo.play.time += (int)demo.play.fraction; demo.play.fraction -= (int)demo.play.fraction; } else if ( demo.find ) { demo.play.time = demo.play.oldTime + 20; demo.play.fraction = 0; if ( demo.play.paused ) demo.find = findNone; } else if (!demo.play.paused) { float delta = demo.play.fraction + deltaTime * demo.play.speed; demo.play.time += (int)delta; demo.play.fraction = delta - (int)delta; } demo.play.lastTime = demo.play.time; if ( demo.loop.total && captureFrame && blurTotal ) { //Delay till we hit the right part at the start int time; float timeFraction; if ( demo.loop.lineDelay && !blurIndex ) { time = demo.loop.start - demo.loop.lineDelay; timeFraction = 0; if ( demo.loop.lineDelay > 8 ) demo.loop.lineDelay -= 8; else demo.loop.lineDelay = 0; captureFrame = qfalse; } else { if ( blurIndex == blurTotal - 1 ) { //We'll restart back to the start again demo.loop.lineDelay = 2000; if ( ++demo.loop.index >= demo.loop.total ) { demo.loop.total = 0; } } time = demo.loop.start; timeFraction = demo.loop.range * blurFraction; } time += (int)timeFraction; timeFraction -= (int)timeFraction; lineAt( time, timeFraction, &demo.line.time, &cg.timeFraction, &frameSpeed ); } else { lineAt( demo.play.time, demo.play.fraction, &demo.line.time, &cg.timeFraction, &frameSpeed ); } /* Set the correct time */ cg.time = trap_MME_SeekTime( demo.line.time ); /* cg.time is shifted ahead a bit to correct some issues.. */ frameSpeed *= demo.play.speed; cg.frametime = (cg.time - cg.oldTime) + (cg.timeFraction - cg.oldTimeFraction); if (cg.frametime < 0) { int i; cg.frametime = 0; hadSkip = qtrue; cg.oldTime = cg.time; cg.oldTimeFraction = cg.timeFraction; CG_InitLocalEntities(); CG_InitMarkPolys(); CG_ClearParticles (); trap_FX_Reset( ); trap_R_DecalReset(); cg.centerPrintTime = 0; cg.damageTime = 0; cg.powerupTime = 0; cg.rewardTime = 0; cg.scoreFadeTime = 0; cg.lastKillTime = 0; cg.attackerTime = 0; cg.soundTime = 0; cg.itemPickupTime = 0; cg.itemPickupBlendTime = 0; cg.weaponSelectTime = 0; cg.headEndTime = 0; cg.headStartTime = 0; cg.v_dmg_time = 0; cg.rewardCount[0] = 0; cg.rewardStack = 0; cg.rewardTime = 0; trap_S_ClearLoopingSounds(qtrue); for (i = 0; i < MAX_CHATBOX_ITEMS; i++) cg.chatItems[i].time = 0; } else if (cg.frametime > 100) { hadSkip = qtrue; } else { hadSkip = qfalse; } /* Make sure the random seed is the same each time we hit this frame */ srand( (cg.time % 10000000) + cg.timeFraction * 1000); /* Prepare to render the screen */ trap_S_ClearLoopingSounds(qfalse); trap_R_ClearScene(); /* Update demo related information */ trap_SetUserCmdValue( cg.weaponSelect, 1 ); demoProcessSnapShots( hadSkip ); if ( !cg.snap ) { CG_DrawInformation(); return; } CG_PreparePacketEntities( ); CG_DemosUpdatePlayer( ); chaseUpdate( demo.play.time, demo.play.fraction ); cameraUpdate( demo.play.time, demo.play.fraction ); dofUpdate( demo.play.time, demo.play.fraction ); demoEffectUpdate( demo.play.time, demo.play.fraction ); cg.clientFrame++; // update cg.predictedPlayerState CG_InterpolatePlayerState( qfalse ); BG_PlayerStateToEntityState( &cg.predictedPlayerState, &cg.predictedPlayerEntity.currentState, qfalse ); if ( cg.cpma.detected ) { if ( cg.predictedPlayerState.pm_type >= 4 ) cg.predictedPlayerEntity.currentState.eType = ET_INVISIBLE; } cg.predictedPlayerEntity.currentValid = qtrue; VectorCopy( cg.predictedPlayerEntity.currentState.pos.trBase, cg.predictedPlayerEntity.lerpOrigin ); VectorCopy( cg.predictedPlayerEntity.currentState.apos.trBase, cg.predictedPlayerEntity.lerpAngles ); inwater = demoSetupView(); CG_TileClear(); trap_FX_Begin( cg.time, cg.timeFraction ); scriptRun( hadSkip ); CG_AddPacketEntities(); CG_AddMarks(); CG_AddParticles (); CG_AddLocalEntities(); if ( cg.playerCent == &cg.predictedPlayerEntity ) { // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); CG_AddViewWeapon( &cg.predictedPlayerState ); } else if ( cg.playerCent && cg.playerCent->currentState.number < MAX_CLIENTS ) { CG_AddViewWeaponDirect( cg.playerCent ); } trap_S_UpdateEntityPosition(ENTITYNUM_NONE, cg.refdef.vieworg); CG_PlayBufferedSounds(); CG_PlayBufferedVoiceChats(); cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); /* Render some extra demo related stuff */ if (!captureFrame) { switch (demo.editType) { case editCamera: cameraDraw( demo.play.time, demo.play.fraction ); break; case editChase: chaseDraw( demo.play.time, demo.play.fraction ); break; case editDof: dofDraw( demo.play.time, demo.play.fraction ); break; case editEffect: demoEffectDraw( demo.play.time, demo.play.fraction ); break; } /* Add bounding boxes for easy aiming */ if ( demo.editType && ( demo.cmd.buttons & BUTTON_ATTACK) && ( demo.cmd.buttons & BUTTON_AFFIRMATIVE) ) { int i; centity_t *targetCent; for (i = 0;i<MAX_GENTITIES;i++) { targetCent = demoTargetEntity( i ); if (targetCent) { vec3_t container, traceStart, traceImpact, forward; const float *color; demoCentityBoxSize( targetCent, container ); VectorSubtract( demo.viewOrigin, targetCent->lerpOrigin, traceStart ); AngleVectors( demo.viewAngles, forward, 0, 0 ); if (BoxTraceImpact( traceStart, forward, container, traceImpact )) { color = colorRed; } else { color = colorYellow; } demoDrawBox( targetCent->lerpOrigin, container, color ); } } } if ( mov_gridStep.value > 0 && mov_gridRange.value > 0) { vec4_t color; vec3_t offset; qhandle_t shader = trap_R_RegisterShader( "mme/gridline" ); color[0] = color[1] = color[2] = 1; color[3] = 0; offset[0] = offset[1] = offset[2] = 0; Q_parseColor( mov_gridColor.string, ospColors, color ); demoDrawGrid( demo.viewOrigin, color, offset, mov_gridWidth.value, mov_gridStep.value, mov_gridRange.value, shader ); } } if (frameSpeed > 5) frameSpeed = 5; trap_S_UpdateScale( frameSpeed ); if (cg.playerCent && cg.predictedPlayerState.pm_type == PM_INTERMISSION) { entityNum = cg.snap->ps.clientNum; } else if (cg.playerCent) { entityNum = cg.playerCent->currentState.number; } else { entityNum = ENTITYNUM_NONE; } trap_S_Respatialize( entityNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater); trap_FX_End(); if (captureFrame && stereoSep > 0.0f) trap_Cvar_Set("r_stereoSeparation", va("%f", -stereoSep)); trap_MME_TimeFraction(cg.timeFraction); trap_R_RenderScene( &cg.refdef ); if ( demo.viewType == viewChase && cg.playerCent && ( cg.playerCent->currentState.number < MAX_CLIENTS ) ) CG_Draw2D(); // CG_DrawSmallString( 0, 0, va( "height %d", cg.playerCent->pe.viewHeight ), 1 ); if (captureFrame) { char fileName[MAX_OSPATH]; Com_sprintf( fileName, sizeof( fileName ), "capture/%s/%s", mme_demoFileName.string, mov_captureName.string ); trap_MME_Capture( fileName, captureFPS, demo.viewFocus, demo.viewRadius ); if ( mov_captureCamera.integer ) demoAddViewPos( fileName, demo.viewOrigin, demo.viewAngles, demo.viewFov ); } else { if (demo.editType && !cg.playerCent) demoDrawCrosshair(); hudDraw(); if (demo.editType) { demoDrawProgress(trap_MME_ProgressTime()); } } //checkCaptureEnd: if ( demo.capture.active && demo.capture.locked && demo.play.time > demo.capture.end ) { Com_Printf( "Capturing ended\n" ); if (demo.autoLoad) { trap_SendConsoleCommand( "disconnect\n" ); } demo.capture.active = qfalse; } }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qbool demoPlayback ) { int inwater; cg.time = serverTime; //unlagged - lag simulation #1 // adjust the clock to reflect latent snaps cg.time -= cg_latentSnaps.integer * (1000 / sv_fps.integer); //unlagged - lag simulation #1 cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity ); // WP_SEC_PISTOL 's special value has been transmitted. // Restore cg.weaponSelect if (cg.weaponSelect == WP_SEC_PISTOL) cg.weaponSelect = cg._weaponSelect; // this counter will be bumped for every valid scene we generate cg.clientFrame++; // check if duel start sound has to be played if(cg.roundstarttime && cg.roundstarttime <= cg.time && cgs.gametype == GT_DUEL) { cg.introstart = cg.roundstarttime; cg.introend = cg.introstart + DU_INTRO_CAM + DU_INTRO_DRAW; cg.roundstarttime = 0; // cycle through the start tracks trap_S_StartLocalSound( cgs.media.duelstart[cg.duelstartsound], CHAN_ANNOUNCER ); cg.duelstartsound++; if(cg.duelstartsound == 5) cg.duelstartsound = 0; } // update cg.predictedPlayerState CG_PredictPlayerState(); // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer || cg.introstart || (cgs.deathcam && (cg.snap->ps.stats[STAT_HEALTH] <= 0) && !(cg.snap->ps.pm_flags & PMF_SUICIDE) && !(cg.snap->ps.pm_flags & PMF_FOLLOW) && (cg.snap->ps.pm_type != PM_CHASECAM) && (cgs.gametype != GT_DUEL)); // build cg.refdef inwater = CG_CalcViewValues(); // build cg_frustum, from cg.refdef CG_SetupFrustum(); // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddLocalEntities(); } CG_AddViewWeapon( &cg.predictedPlayerState ); // add buffered sounds CG_PlayBufferedSounds(); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; if ( cg.frametime < 0 ) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive( stereoView ); if ( cg_stats.integer ) { CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } }