/* * CG_Democam_UnregisterSubtitle */ static void CG_Democam_UnregisterSubtitle( cg_subtitle_t *sub ) { cg_subtitle_t *tsub; if( !sub ) { return; } // headnode shortcut if( cg_subs_headnode == sub ) { cg_subs_headnode = cg_subs_headnode->next; if( sub->text ) { CG_Free( sub->text ); } CG_Free( sub ); return; } // find the camera which has this one as next; tsub = cg_subs_headnode; while( tsub != NULL ) { if( tsub->next == sub ) { tsub->next = sub->next; if( sub->text ) { CG_Free( sub->text ); } CG_Free( sub ); break; } tsub = tsub->next; } }
/* * CG_Democam_UnregisterCam */ static void CG_Democam_UnregisterCam( cg_democam_t *cam ) { cg_democam_t *tcam; if( !cam ) { return; } // headnode shortcut if( cg_cams_headnode == cam ) { cg_cams_headnode = cg_cams_headnode->next; CG_Free( cam ); return; } // find the camera which has this one as next; tcam = cg_cams_headnode; while( tcam != NULL ) { if( tcam->next == cam ) { tcam->next = cam->next; CG_Free( cam ); break; } tcam = tcam->next; } }
/* * CG_AsyncGetRequest_DoneCb */ static void CG_AsyncGetRequest_DoneCb( int status, const char *contentType, void *privatep ) { cg_asyncrequest_t *req = ( cg_asyncrequest_t * )privatep; req->done_cb( status, req->buf ); CG_Free( req->buf ); CG_Free( req ); }
/* * CG_DemocamInit */ void CG_DemocamInit( void ) { int name_size; bool hassoundstream = false; democam_editing_mode = false; demo_initial_timestamp = 0; if( !cgs.demoPlaying ) return; if( !*cgs.demoName ) CG_Error( "CG_LoadRecamScriptFile: no demo name string\n" ); // see if there is any script for this demo, and load it name_size = sizeof( char ) * ( strlen( cgs.demoName ) + strlen( ".cam" ) + 1 ); demoscriptname = ( char * )CG_Malloc( name_size ); Q_snprintfz( demoscriptname, name_size, "%s", cgs.demoName ); COM_ReplaceExtension( demoscriptname, ".cam", name_size ); CG_Printf( "cam: %s\n", demoscriptname ); // add console commands trap_Cmd_AddCommand( "demoEditMode", CG_DemoEditMode_Cmd_f ); trap_Cmd_AddCommand( "demoFreeFly", CG_DemoFreeFly_Cmd_f ); trap_Cmd_AddCommand( "camswitch", CG_CamSwitch_Cmd_f ); if( CG_LoadRecamScriptFile( demoscriptname ) ) { CG_Printf( "Loaded demo cam script\n" ); } // check for a sound stream file cgs.demoAudioStream = ( char * )CG_Malloc( name_size ); Q_snprintfz( cgs.demoAudioStream, name_size, "%s", cgs.demoName ); COM_ReplaceExtension( cgs.demoAudioStream, ".wav", name_size ); if( trap_FS_FOpenFile( cgs.demoAudioStream, NULL, FS_READ ) != -1 ) { hassoundstream = true; } else { COM_ReplaceExtension( cgs.demoAudioStream, ".ogg", name_size ); if( trap_FS_FOpenFile( cgs.demoAudioStream, NULL, FS_READ ) != -1 ) { hassoundstream = true; } } if( !hassoundstream ) { CG_Free( cgs.demoAudioStream ); cgs.demoAudioStream = NULL; } }
/* * CG_ExpandTemporaryBoneposesCache */ static void CG_ExpandTemporaryBoneposesCache( int num ) { bonepose_t *temp; temp = TBC; TBC = CG_Malloc( sizeof( bonepose_t ) * ( TBC_Size + max( num, TBC_Block_Size ) ) ); memcpy( TBC, temp, sizeof( bonepose_t ) * TBC_Size ); TBC_Size += max( num, TBC_Block_Size ); CG_Free( temp ); }
/* * CG_CS_UpdateTeamInfo */ static void CG_CS_UpdateTeamInfo( void ) { char *ti; ti = trap_Cmd_Argv( 1 ); if( !ti[0] ) { cg.teaminfo_size = 0; CG_Free( cg.teaminfo ); cg.teaminfo = NULL; return; } if( strlen( ti ) + 1 > cg.teaminfo_size ) { if( cg.teaminfo ) CG_Free( cg.teaminfo ); cg.teaminfo_size = strlen( ti ) + 1; cg.teaminfo = CG_Malloc( cg.teaminfo_size ); } Q_strncpyz( cg.teaminfo, ti, cg.teaminfo_size ); }
/* * CG_FreeLocalEntity */ static void CG_FreeLocalEntity( lentity_t *le ) { if( le->static_boneposes ) { CG_Free( le->static_boneposes ); le->static_boneposes = NULL; } // remove from linked active list le->prev->next = le->next; le->next->prev = le->prev; // insert into linked free list le->next = cg_free_lents; cg_free_lents = le; }
/* * CG_DemocamShutdown */ void CG_DemocamShutdown( void ) { if( !cgs.demoPlaying ) { return; } // remove console commands trap_Cmd_RemoveCommand( "demoEditMode" ); trap_Cmd_RemoveCommand( "demoFreeFly" ); trap_Cmd_RemoveCommand( "camswitch" ); if( democam_editing_mode ) { CG_DemoEditMode_RemoveCmds(); } CG_Democam_FreeCams(); CG_Democam_FreeSubtitles(); CG_Free( demoscriptname ); demoscriptname = NULL; }
/* * CG_SaveCam_Cmd_f */ void CG_SaveCam_Cmd_f( void ) { if( !cgs.demoPlaying ) { return; } if( trap_Cmd_Argc() > 1 ) { char *customName; int custom_name_size; custom_name_size = sizeof( char ) * ( strlen( "demos/" ) + strlen( trap_Cmd_Argv( 1 ) ) + strlen( ".cam" ) + 1 ); customName = ( char * )CG_Malloc( custom_name_size ); Q_snprintfz( customName, custom_name_size, "demos/%s", trap_Cmd_Argv( 1 ) ); COM_ReplaceExtension( customName, ".cam", custom_name_size ); CG_SaveRecamScriptFile( customName ); CG_Free( customName ); return; } CG_SaveRecamScriptFile( demoscriptname ); }
/* * CG_AsyncGetRequest_ReadCb */ static size_t CG_AsyncGetRequest_ReadCb( const void *buf, size_t numb, float percentage, int status, const char *contentType, void *privatep ) { char *newbuf; cg_asyncrequest_t *req = ( cg_asyncrequest_t * )privatep; if( status < 0 || status >= 300 ) { return 0; } newbuf = ( char * )CG_Malloc( req->buf_size + numb + 1 ); memcpy( newbuf, req->buf, req->buf_size - 1 ); memcpy( newbuf + req->buf_size - 1, buf, numb ); newbuf[numb] = '\0'; // EOF CG_Free( req->buf ); req->buf = newbuf; req->buf_size = req->buf_size + numb + 1; return numb; }
/* * CG_SC_MOTD */ static void CG_SC_MOTD( void ) { char *motd; if( cg.motd ) CG_Free( cg.motd ); cg.motd = NULL; motd = trap_Cmd_Argv( 2 ); if( !motd[0] ) return; if( !strcmp( trap_Cmd_Argv( 1 ), "1" ) ) { cg.motd = CG_CopyString( motd ); cg.motd_time = cg.time + 50 *strlen( motd ); if( cg.motd_time < cg.time + 5000 ) cg.motd_time = cg.time + 5000; } CG_Printf( "\nMessage of the Day:\n%s", motd ); }
/* * CG_vWeap_ParseAnimationScript * * script: * 0 = first frame * 1 = lastframe/number of frames * 2 = looping frames * 3 = frame time * * keywords: * "islastframe":Will read the second value of each animation as lastframe (usually means numframes) * "rotationscale": value witch will scale the barrel rotation speed */ static bool CG_vWeap_ParseAnimationScript( weaponinfo_t *weaponinfo, char *filename ) { qbyte *buf; char *ptr, *token; int rounder, counter, i; bool debug = true; int anim_data[4][VWEAP_MAXANIMS]; int length, filenum; rounder = 0; counter = 1; // reserve 0 for 'no animation' // set some defaults weaponinfo->barrelSpeed = 0; weaponinfo->flashFade = true; if( !cg_debugWeaponModels->integer ) debug = false; // load the file length = trap_FS_FOpenFile( filename, &filenum, FS_READ ); if( length == -1 ) return false; if( !length ) { trap_FS_FCloseFile( filenum ); return false; } buf = ( qbyte * )CG_Malloc( length + 1 ); trap_FS_Read( buf, length, filenum ); trap_FS_FCloseFile( filenum ); if( !buf ) { CG_Free( buf ); return false; } if( debug ) CG_Printf( "%sLoading weapon animation script:%s%s\n", S_COLOR_BLUE, filename, S_COLOR_WHITE ); memset( anim_data, 0, sizeof( anim_data ) ); //proceed ptr = ( char * )buf; while( ptr ) { token = COM_ParseExt( &ptr, qtrue ); if( !token[0] ) break; //see if it is keyword or number if( *token < '0' || *token > '9' ) { if( !Q_stricmp( token, "barrel" ) ) { if( debug ) CG_Printf( "%sScript: barrel:%s", S_COLOR_BLUE, S_COLOR_WHITE ); // time i = atoi( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->barrelTime = (unsigned int)( i > 0 ? i : 0 ); // speed weaponinfo->barrelSpeed = atof( COM_ParseExt( &ptr, qfalse ) ); if( debug ) CG_Printf( "%s time:%i, speed:%.2f\n", S_COLOR_BLUE, (int)weaponinfo->barrelTime, weaponinfo->barrelSpeed, S_COLOR_WHITE ); } else if( !Q_stricmp( token, "flash" ) ) { if( debug ) CG_Printf( "%sScript: flash:%s", S_COLOR_BLUE, S_COLOR_WHITE ); // time i = atoi( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->flashTime = (unsigned int)( i > 0 ? i : 0 ); // radius i = atoi( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->flashRadius = (float)( i > 0 ? i : 0 ); // fade token = COM_ParseExt( &ptr, qfalse ); if( !Q_stricmp( token, "no" ) ) weaponinfo->flashFade = false; if( debug ) CG_Printf( "%s time:%i, radius:%i, fade:%s%s\n", S_COLOR_BLUE, (int)weaponinfo->flashTime, (int)weaponinfo->flashRadius, weaponinfo->flashFade ? "YES" : "NO", S_COLOR_WHITE ); } else if( !Q_stricmp( token, "flashColor" ) ) { if( debug ) CG_Printf( "%sScript: flashColor:%s", S_COLOR_BLUE, S_COLOR_WHITE ); weaponinfo->flashColor[0] = atof( token = COM_ParseExt( &ptr, qfalse ) ); weaponinfo->flashColor[1] = atof( token = COM_ParseExt( &ptr, qfalse ) ); weaponinfo->flashColor[2] = atof( token = COM_ParseExt( &ptr, qfalse ) ); if( debug ) CG_Printf( "%s%f %f %f%s\n", S_COLOR_BLUE, weaponinfo->flashColor[0], weaponinfo->flashColor[1], weaponinfo->flashColor[2], S_COLOR_WHITE ); } else if( !Q_stricmp( token, "handOffset" ) ) { if( debug ) CG_Printf( "%sScript: handPosition:%s", S_COLOR_BLUE, S_COLOR_WHITE ); weaponinfo->handpositionOrigin[FORWARD] = atof( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->handpositionOrigin[RIGHT] = atof( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->handpositionOrigin[UP] = atof( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->handpositionAngles[PITCH] = atof( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->handpositionAngles[YAW] = atof( COM_ParseExt( &ptr, qfalse ) ); weaponinfo->handpositionAngles[ROLL] = atof( COM_ParseExt( &ptr, qfalse ) ); if( debug ) CG_Printf( "%s%f %f %f %f %f %f%s\n", S_COLOR_BLUE, weaponinfo->handpositionOrigin[0], weaponinfo->handpositionOrigin[1], weaponinfo->handpositionOrigin[2], weaponinfo->handpositionAngles[0], weaponinfo->handpositionAngles[1], weaponinfo->handpositionAngles[2], S_COLOR_WHITE ); } else if( !Q_stricmp( token, "firesound" ) ) { if( debug ) CG_Printf( "%sScript: firesound:%s", S_COLOR_BLUE, S_COLOR_WHITE ); if( weaponinfo->num_fire_sounds >= WEAPONINFO_MAX_FIRE_SOUNDS ) { if( debug ) CG_Printf( S_COLOR_BLUE "too many firesounds defined. Max is %i" S_COLOR_WHITE "\n", WEAPONINFO_MAX_FIRE_SOUNDS ); break; } token = COM_ParseExt( &ptr, qfalse ); if( Q_stricmp( token, "NULL" ) ) { weaponinfo->sound_fire[weaponinfo->num_fire_sounds] = trap_S_RegisterSound( token ); if( weaponinfo->sound_fire[weaponinfo->num_fire_sounds] != NULL ) weaponinfo->num_fire_sounds++; } if( debug ) CG_Printf( "%s%s%s\n", S_COLOR_BLUE, token, S_COLOR_WHITE ); } else if( !Q_stricmp( token, "strongfiresound" ) ) { if( debug ) CG_Printf( "%sScript: strongfiresound:%s", S_COLOR_BLUE, S_COLOR_WHITE ); if( weaponinfo->num_strongfire_sounds >= WEAPONINFO_MAX_FIRE_SOUNDS ) { if( debug ) CG_Printf( S_COLOR_BLUE "too many strongfiresound defined. Max is %i" S_COLOR_WHITE "\n", WEAPONINFO_MAX_FIRE_SOUNDS ); break; } token = COM_ParseExt( &ptr, qfalse ); if( Q_stricmp( token, "NULL" ) ) { weaponinfo->sound_strongfire[weaponinfo->num_strongfire_sounds] = trap_S_RegisterSound( token ); if( weaponinfo->sound_strongfire[weaponinfo->num_strongfire_sounds] != NULL ) weaponinfo->num_strongfire_sounds++; } if( debug ) CG_Printf( "%s%s%s\n", S_COLOR_BLUE, token, S_COLOR_WHITE ); } else if( token[0] && debug ) CG_Printf( "%signored: %s%s\n", S_COLOR_YELLOW, token, S_COLOR_WHITE ); } else { //frame & animation values i = (int)atoi( token ); if( debug ) { if( rounder == 0 ) CG_Printf( "%sScript: %s", S_COLOR_BLUE, S_COLOR_WHITE ); CG_Printf( "%s%i - %s", S_COLOR_BLUE, i, S_COLOR_WHITE ); } anim_data[rounder][counter] = i; rounder++; if( rounder > 3 ) { rounder = 0; if( debug ) CG_Printf( "%s anim: %i%s\n", S_COLOR_BLUE, counter, S_COLOR_WHITE ); counter++; if( counter == VWEAP_MAXANIMS ) break; } } } CG_Free( buf ); if( counter < VWEAP_MAXANIMS ) { CG_Printf( "%sERROR: incomplete WEAPON script: %s - Using default%s\n", S_COLOR_YELLOW, filename, S_COLOR_WHITE ); return false; } //reorganize to make my life easier for( i = 0; i < VWEAP_MAXANIMS; i++ ) { weaponinfo->firstframe[i] = anim_data[0][i]; weaponinfo->lastframe[i] = anim_data[1][i]; weaponinfo->loopingframes[i] = anim_data[2][i]; if( anim_data[3][i] < 10 ) //never allow less than 10 fps anim_data[3][i] = 10; weaponinfo->frametime[i] = 1000/anim_data[3][i]; } return true; }
/* * CG_GS_Free * * Used only for gameshared linking */ static void CG_GS_Free( void *data ) { CG_Free( data ); }
/* * CG_LoadRecamScriptFile */ bool CG_LoadRecamScriptFile( char *filename ) { int filelen, filehandle; uint8_t *buf = NULL; char *ptr, *token; int linecount; cg_democam_t *cam = NULL; if( !filename ) { CG_Printf( "CG_LoadRecamScriptFile: no filename\n" ); return false; } filelen = trap_FS_FOpenFile( filename, &filehandle, FS_READ ); if( !filehandle || filelen < 1 ) { trap_FS_FCloseFile( filehandle ); } else { buf = ( uint8_t * )CG_Malloc( filelen + 1 ); filelen = trap_FS_Read( buf, filelen, filehandle ); trap_FS_FCloseFile( filehandle ); } if( !buf ) { return false; } // parse the script linecount = 0; ptr = ( char * )buf; while( ptr ) { token = COM_ParseExt( &ptr, true ); if( !token[0] ) { break; } if( !Q_stricmp( token, "subtitle" ) || !Q_stricmp( token, "print" ) ) { cg_subtitle_t *sub; sub = CG_Democam_RegisterSubtitle(); sub->highprint = ( Q_stricmp( token, "print" ) == 0 ); token = COM_ParseExt( &ptr, true ); if( !token[0] ) { break; } sub->timeStamp = (unsigned int)atoi( token ); token = COM_ParseExt( &ptr, true ); if( !token[0] ) { break; } sub->maxDuration = (unsigned int)atoi( token ); sub->text = CG_CopyString( COM_ParseExt( &ptr, true ) ); linecount = 0; } else { switch( linecount ) { case 0: cam = CG_Democam_RegisterCam( atoi( token ) ); break; case 1: cam->timeStamp = (unsigned int)atoi( token ); break; case 2: cam->origin[0] = atof( token ); break; case 3: cam->origin[1] = atof( token ); break; case 4: cam->origin[2] = atof( token ); break; case 5: cam->angles[0] = atof( token ); break; case 6: cam->angles[1] = atof( token ); break; case 7: cam->angles[2] = atof( token ); break; case 8: cam->trackEnt = atoi( token ); break; case 9: cam->fov = atoi( token ); break; default: CG_Error( "CG_LoadRecamScriptFile: bad switch\n" ); } linecount++; if( linecount == 10 ) { linecount = 0; } } } CG_Free( buf ); if( linecount != 0 ) { CG_Printf( "CG_LoadRecamScriptFile: Invalid script. Ignored\n" ); CG_Democam_FreeCams(); CG_Democam_FreeSubtitles(); return false; } CG_Democam_ExecutePathAnalysis(); return true; }