void Conbuf_AppendText( const char *pMsg ) { char msg[4096] = {0}; Q_strncpyz(msg, pMsg, sizeof(msg)); Q_StripColor(msg); printf("%s", msg); }
/* ================== SV_KickBlankPlayers ================== */ static void SV_KickBlankPlayers( void ) { client_t *cl; int i; char cleanName[64]; // make sure server is running if ( !com_sv_running->integer ) { return; } // check for a name match for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { continue; } if ( !Q_stricmp( cl->name, "" ) ) { SV_DropClient( cl, SV_GetStringEdString("MP_SVGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie continue; } Q_strncpyz( cleanName, cl->name, sizeof(cleanName) ); Q_StripColor( cleanName ); //Q_CleanStr( cleanName ); if ( !Q_stricmp( cleanName, "" ) ) { SV_DropClient( cl, SV_GetStringEdString("MP_SVGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } }
/* ================== CON_Print ================== */ void CON_Print( const char *msg ) { char cmsg[MAXPRINTMSG] = { 0 }; Q_strncpyz( cmsg, msg, sizeof( cmsg ) ); Q_StripColor( cmsg ); printf( "%s", cmsg ); }
/* =================== ClientForString =================== */ gclient_t *ClientForString( const char *s ) { gclient_t *cl; int idnum; char cleanInput[MAX_STRING_CHARS]; // numeric values could be slot numbers if ( StringIsInteger( s ) ) { idnum = atoi( s ); if ( idnum >= 0 && idnum < level.maxclients ) { cl = &level.clients[idnum]; if ( cl->pers.connected == CON_CONNECTED ) { return cl; } } } Q_strncpyz( cleanInput, s, sizeof(cleanInput) ); Q_StripColor( cleanInput ); // check for a name match for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) { if ( cl->pers.connected != CON_CONNECTED ) { continue; } if ( !Q_stricmp( cl->pers.netname_nocolor, cleanInput ) ) { return cl; } } trap->Print( "User %s is not on the server\n", s ); return NULL; }
/* ================== SV_GetPlayerByHandle Returns the player with player id or name from Cmd_Argv(1) ================== */ static client_t *SV_GetPlayerByHandle( void ) { client_t *cl; int i; char *s; char cleanName[64]; // make sure server is running if ( !com_sv_running->integer ) { return NULL; } if ( Cmd_Argc() < 2 ) { Com_Printf( "No player specified.\n" ); return NULL; } s = Cmd_Argv(1); // Check whether this is a numeric player handle for(i = 0; s[i] >= '0' && s[i] <= '9'; i++); if(!s[i]) { int plid = atoi(s); // Check for numeric playerid match if(plid >= 0 && plid < sv_maxclients->integer) { cl = &svs.clients[plid]; if(cl->state) return cl; } } // check for a name match for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if ( !Q_stricmp( cl->name, s ) ) { return cl; } Q_strncpyz( cleanName, cl->name, sizeof(cleanName) ); Q_StripColor( cleanName ); //Q_CleanStr( cleanName ); if ( !Q_stricmp( cleanName, s ) ) { return cl; } } Com_Printf( "Player %s is not on the server\n", s ); return NULL; }
static void SV_NetStatus_f(void) { char netStatus[4096] = {0}; int i; char cleanName[MAX_NETNAME] = {0}; client_t *cl; playerState_t *ps; Q_strcat(netStatus, sizeof(netStatus), "\n"); Q_strcat(netStatus, sizeof(netStatus), "ID Score Ping Name LastMSG Address QPort Rate\n"); Q_strcat(netStatus, sizeof(netStatus), "-- ----- ---- --------------- ------- --------------------- ----- -----\n"); for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { if (!cl->state) { continue; } Q_strcat(netStatus, sizeof(netStatus), va("%2i ", i)); //ID ps = SV_GameClientNum(i); Q_strcat(netStatus, sizeof(netStatus), va("%5i ", ps->persistant[PERS_SCORE])); //Score if (cl->state == CS_CONNECTED) Q_strcat(netStatus, sizeof(netStatus), "CNCT "); //Ping else if (cl->state == CS_ZOMBIE) Q_strcat(netStatus, sizeof(netStatus), "ZMBI "); //Ping else Q_strcat(netStatus, sizeof(netStatus), va("%4i ", cl->ping < 999 ? cl->ping : 999)); //Ping //FIXME: stripcolor until we fix alignment Q_strncpyz(cleanName, cl->name, sizeof(cleanName)); Q_StripColor(cleanName); Q_strcat(netStatus, sizeof(netStatus), va("%-15.15s ", cleanName)); //Name Q_strcat(netStatus, sizeof(netStatus), va("%7i ", svs.time - cl->lastPacketTime)); //LastMSG Q_strcat(netStatus, sizeof(netStatus), va("%21s ", NET_AdrToString(cl->netchan.remoteAddress))); //Address Q_strcat(netStatus, sizeof(netStatus), va("%5i ", cl->netchan.qport)); //QPort Q_strcat(netStatus, sizeof(netStatus), va("%5i ", cl->rate)); //Rate } Q_strcat(netStatus, sizeof(netStatus), "\n"); Com_Printf(netStatus); }
/* ============= Com_Printf Both client and server can use this, and it will output to the apropriate place. A raw string should NEVER be passed as fmt, because of "%f" type crashers. ============= */ void QDECL Com_Printf( const char *fmt, ... ) { va_list argptr; char msg[MAXPRINTMSG]; va_start (argptr,fmt); Q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); if ( rd_buffer ) { if ((strlen (msg) + strlen(rd_buffer)) > (unsigned)(rd_buffersize - 1)) { rd_flush(rd_buffer); *rd_buffer = 0; } Q_strcat (rd_buffer, strlen(rd_buffer), msg); return; } CL_ConsolePrint( msg ); // Strip out color codes because these aren't needed in the log/viewlog or in the output window --eez Q_StripColor( msg ); // echo to dedicated console and early console Sys_Print( msg ); #ifdef OUTPUT_TO_BUILD_WINDOW OutputDebugString(msg); #endif // logfile if ( com_logfile && com_logfile->integer ) { if ( !logfile ) { logfile = FS_FOpenFileWrite( "qconsole.log" ); if ( com_logfile->integer > 1 ) { // force it to not buffer so we get valid // data even if we are crashing FS_ForceFlush(logfile); } } if ( logfile ) { FS_Write(msg, strlen(msg), logfile); } } }
//Func: GetPlayer(clientNum) //Retn: Player object if their clientinfo is valid, and clientNum is between [0, MAX_CLIENTS-1] int JPLua_GetPlayer( lua_State *L ) { int num = -1; unsigned int clientsFound = 0; if ( lua_type( L, 1 ) == LUA_TNIL ) num = cg.clientNum; else if ( lua_type( L, 1 ) == LUA_TNUMBER ) num = lua_tointeger( L, 1 ); if ( lua_type( L, 1 ) == LUA_TSTRING ) { const char *name = lua_tostring( L, 1 ); int numFound = 0; int i=0; for ( i=0; i<cgs.maxclients; i++ ) { char nameClean[36] = {0}; char nameClean2[36] = {0}; if ( !cgs.clientinfo[i].infoValid ) continue; Q_strncpyz( nameClean, cgs.clientinfo[i].name, sizeof( nameClean ) ); Q_strncpyz( nameClean2, name, sizeof( nameClean2 ) ); Q_StripColor( nameClean ); Q_StripColor( nameClean2 ); if ( !Q_stricmp( nameClean, nameClean2 ) ) { num = i; clientsFound |= (1<<i); numFound++; } } if ( numFound > 1 ) { int top=0; lua_pushnil( L ); lua_pushstring( L, "Multiple matches" ); lua_newtable( L ); top = lua_gettop( L ); for ( i=0; i<cgs.maxclients; i++ ) { if ( clientsFound & (1<<i) ) { lua_pushnumber( L, i ); JPLua_Player_CreateRef( L, i ); lua_settable( L, top ); } } return 3; } else if ( !numFound ) { lua_pushnil( L ); return 1; } } JPLua_Player_CreateRef( L, num ); return 1; }
/* ================ SV_Status_f ================ */ static void SV_Status_f( void ) { int i, humans, bots; client_t *cl; playerState_t *ps; const char *s; int ping; char state[32]; qboolean avoidTruncation = qfalse; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() > 1 ) { if (!Q_stricmp("notrunc", Cmd_Argv(1))) { avoidTruncation = qtrue; } } humans = bots = 0; for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { if ( svs.clients[i].netchan.remoteAddress.type != NA_BOT ) { humans++; } else { bots++; } } } #if defined(_WIN32) #define STATUS_OS "Windows" #elif defined(__linux__) #define STATUS_OS "Linux" #elif defined(MACOS_X) #define STATUS_OS "OSX" #else #define STATUS_OS "Unknown" #endif const char *ded_table[] = { "listen", "lan dedicated", "public dedicated", }; char hostname[MAX_HOSTNAMELENGTH] = { 0 }; Q_strncpyz( hostname, sv_hostname->string, sizeof(hostname) ); Q_StripColor( hostname ); Com_Printf( "hostname: %s^7\n", hostname ); Com_Printf( "version : %s %i\n", VERSION_STRING_DOTTED, PROTOCOL_VERSION ); Com_Printf( "game : %s\n", FS_GetCurrentGameDir() ); Com_Printf( "udp/ip : %s:%i os(%s) type(%s)\n", Cvar_VariableString( "net_ip" ), Cvar_VariableIntegerValue( "net_port" ), STATUS_OS, ded_table[com_dedicated->integer] ); Com_Printf( "map : %s gametype(%i)\n", sv_mapname->string, sv_gametype->integer ); Com_Printf( "players : %i humans, %i bots (%i max)\n", humans, bots, sv_maxclients->integer - sv_privateClients->integer ); Com_Printf( "uptime : %s\n", SV_CalcUptime() ); Com_Printf ("cl score ping name address rate \n"); Com_Printf ("-- ----- ---- --------------- --------------------------------------- -----\n"); for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( !cl->state ) continue; if ( cl->state == CS_CONNECTED ) Q_strncpyz( state, "CON ", sizeof( state ) ); else if ( cl->state == CS_ZOMBIE ) Q_strncpyz( state, "ZMB ", sizeof( state ) ); else { ping = cl->ping < 9999 ? cl->ping : 9999; Com_sprintf( state, sizeof(state), "%4i", ping ); } ps = SV_GameClientNum( i ); s = NET_AdrToString( cl->netchan.remoteAddress ); if (!avoidTruncation) { Com_Printf ("%2i %5i %s %-15.15s ^7%39s %5i\n", i, ps->persistant[PERS_SCORE], state, cl->name, s, cl->rate ); } else { Com_Printf ("%2i %5i %s %s ^7%39s %5i\n", i, ps->persistant[PERS_SCORE], state, cl->name, s, cl->rate ); } } Com_Printf ("\n"); }
static void CG_ServerCommand( void ) { const char *cmd; char text[MAX_SAY_TEXT]; qboolean IRCG = qfalse; if ( JPLua_Event_ServerCommand() ) return; cmd = CG_Argv(0); if ( !cmd[0] ) { // server claimed the command return; } #if 0 // never seems to get used -Ste if ( !strcmp( cmd, "spd" ) ) { const char *ID; int holdInt,count,i; char string[1204]; count = trap->Cmd_Argc(); ID = CG_Argv(1); holdInt = atoi(ID); memset( &string, 0, sizeof( string ) ); Com_sprintf( string,sizeof(string)," \"%s\"", (const char *) CG_Argv(2)); for (i=3;i<count;i++) { Com_sprintf( string,sizeof(string)," %s \"%s\"", string, (const char *) CG_Argv(i)); } trap->SP_Print(holdInt, (byte *)string); return; } #endif if (!strcmp(cmd, "sxd")) { //siege extended data, contains extra info certain classes may want to know about other clients CG_ParseSiegeExtendedData(); return; } if (!strcmp(cmd, "sb")) { //siege briefing display CG_SiegeBriefingDisplay(atoi(CG_Argv(1)), 0); return; } if ( !strcmp( cmd, "scl" ) ) { //if (!( trap->Key_GetCatcher() & KEYCATCH_UI )) //Well, I want it to come up even if the briefing display is up. { trap->OpenUIMenu(UIMENU_CLASSSEL); //UIMENU_CLASSSEL } return; } if ( !strcmp( cmd, "spc" ) ) { trap->Cvar_Set("ui_myteam", "3"); trap->OpenUIMenu(UIMENU_PLAYERCONFIG); //UIMENU_CLASSSEL return; } if ( !strcmp( cmd, "nfr" ) ) { //"nfr" == "new force rank" (want a short string) int doMenu = 0; int setTeam = 0; int newRank = 0; if (trap->Cmd_Argc() < 3) { #ifdef _DEBUG Com_Printf("WARNING: Invalid newForceRank string\n"); #endif return; } newRank = atoi(CG_Argv(1)); doMenu = atoi(CG_Argv(2)); setTeam = atoi(CG_Argv(3)); trap->Cvar_Set("ui_rankChange", va("%i", newRank)); trap->Cvar_Set("ui_myteam", va("%i", setTeam)); if (!( trap->Key_GetCatcher() & KEYCATCH_UI ) && doMenu) { trap->OpenUIMenu(UIMENU_PLAYERCONFIG); } return; } if ( !strcmp( cmd, "kg2" ) ) { //Kill a ghoul2 instance in this slot. //If it has been occupied since this message was sent somehow, the worst that can (should) happen //is the instance will have to reinit with its current info. int indexNum = 0; int argNum = trap->Cmd_Argc(); int i = 1; if (argNum < 1) { return; } while (i < argNum) { indexNum = atoi(CG_Argv(i)); if (cg_entities[indexNum].ghoul2 && trap->G2_HaveWeGhoul2Models(cg_entities[indexNum].ghoul2)) { if (indexNum < MAX_CLIENTS) { //You try to do very bad thing! #ifdef _DEBUG Com_Printf("WARNING: Tried to kill a client ghoul2 instance with a kg2 command!\n"); #endif return; } CG_KillCEntityG2(indexNum); } i++; } return; } if (!strcmp(cmd, "kls")) { //kill looping sounds int indexNum = 0; int argNum = trap->Cmd_Argc(); centity_t *clent = NULL; centity_t *trackerent = NULL; if (argNum < 1) { assert(0); return; } indexNum = atoi(CG_Argv(1)); if (indexNum != -1) { clent = &cg_entities[indexNum]; } if (argNum >= 2) { indexNum = atoi(CG_Argv(2)); if (indexNum != -1) { trackerent = &cg_entities[indexNum]; } } if (clent) { CG_S_StopLoopingSound(clent->currentState.number, -1); } if (trackerent) { CG_S_StopLoopingSound(trackerent->currentState.number, -1); } return; } if (!strcmp(cmd, "ircg")) { //this means param 2 is the body index and we want to copy to bodyqueue on it IRCG = qtrue; } if (!strcmp(cmd, "rcg") || IRCG) { //rcg - Restore Client Ghoul (make sure limbs are reattached and ragdoll state is reset - this must be done reliably) int indexNum = 0; int argNum = trap->Cmd_Argc(); centity_t *clent; if (argNum < 1) { assert(0); return; } indexNum = atoi(CG_Argv(1)); if (indexNum < 0 || indexNum >= MAX_CLIENTS) { assert(0); return; } clent = &cg_entities[indexNum]; //assert(clent->ghoul2); if (!clent->ghoul2) { //this can happen while connecting as a client return; } #ifdef _DEBUG if (!trap->G2_HaveWeGhoul2Models(clent->ghoul2)) { assert(!"Tried to reset state on a bad instance. Crash is inevitable."); } #endif if (IRCG) { int bodyIndex = 0; int weaponIndex = 0; int side = 0; centity_t *body; assert(argNum >= 3); bodyIndex = atoi(CG_Argv(2)); weaponIndex = atoi(CG_Argv(3)); side = atoi(CG_Argv(4)); body = &cg_entities[bodyIndex]; if (side) { body->teamPowerType = qtrue; //light side } else { body->teamPowerType = qfalse; //dark side } CG_BodyQueueCopy(body, clent->currentState.number, weaponIndex); } //reattach any missing limbs if (clent->torsoBolt) { CG_ReattachLimb(clent); } //make sure ragdoll state is reset if (clent->isRagging) { clent->isRagging = qfalse; trap->G2API_SetRagDoll(clent->ghoul2, NULL); //calling with null parms resets to no ragdoll. } //clear all the decals as well trap->G2API_ClearSkinGore(clent->ghoul2); clent->weapon = 0; clent->ghoul2weapon = NULL; //force a weapon reinit return; } if ( !strcmp( cmd, "cp" ) ) { char strEd[MAX_STRINGED_SV_STRING]; CG_CheckSVStringEdRef(strEd, CG_Argv(1)); CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); return; } if ( !strcmp( cmd, "cps" ) ) { char strEd[MAX_STRINGED_SV_STRING]; char *x = (char *)CG_Argv(1); if (x[0] == '@') { x++; } trap->SE_GetStringTextString(x, strEd, MAX_STRINGED_SV_STRING); //Raz: From OJP // CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.20, BIGCHAR_WIDTH ); return; } if ( !strcmp( cmd, "cs" ) ) { CG_ConfigStringModified(); return; } if ( !strcmp( cmd, "print" ) ) { char strEd[MAX_STRINGED_SV_STRING]; CG_CheckSVStringEdRef(strEd, CG_Argv(1)); CG_LogPrintf( cg.log.console, strEd ); trap->Print( "%s", strEd ); return; } if ( !strcmp( cmd, "chat" ) ) { char *msg = JPLua_Event_ChatMessageRecieved( CG_Argv(1) ); //If a JPLua plugin cancelled it, bail if ( !msg ) return; if ( !cg_teamChatsOnly.integer ) { char cbName[MAX_CHATBOX_IDENTIFIER_SIZE] = "normal"; trap->S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); Q_strncpyz( text, msg, MAX_SAY_TEXT ); if ( CG_ContainsChannelEscapeChar( text ) ) Q_strncpyz( cbName, CG_RemoveChannelEscapeChar( text ), sizeof( cbName ) ); CG_RemoveChatEscapeChar( text ); CG_LogPrintf( cg.log.console, va( "%s\n", text ) ); if ( cg_newChatbox.integer ) JP_ChatboxAdd( text, qfalse, cbName ); else CG_ChatBox_AddString( text ); trap->Print( "*%s\n", text ); Q_StripColor( text ); CG_LogPrintf( cg.log.chat, va( "%s\n", text ) ); } return; } if ( !strcmp( cmd, "tchat" ) ) { trap->S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); CG_RemoveChatEscapeChar( text ); CG_LogPrintf( cg.log.console, va( "%s\n", text ) ); if ( cg_newChatbox.integer ) JP_ChatboxAdd( text, qfalse, "team" ); else CG_ChatBox_AddString( text ); trap->Print( "*%s\n", text ); Q_StripColor( text ); CG_LogPrintf( cg.log.chat, va( "%s\n", text ) ); return; } //chat with location, possibly localized. if ( !strcmp( cmd, "lchat" ) ) { if ( !cg_teamChatsOnly.integer ) { char name[MAX_STRING_CHARS]; char loc[MAX_STRING_CHARS]; char color[8]; char message[MAX_STRING_CHARS]; if (trap->Cmd_Argc() < 4) { return; } Q_strncpyz( name, CG_Argv( 1 ), sizeof( name ) ); Q_strncpyz( loc, CG_Argv( 2 ), sizeof( loc ) ); Q_strncpyz( color, CG_Argv( 3 ), sizeof( color ) ); Q_strncpyz( message, CG_Argv( 4 ), sizeof( message ) ); if (loc[0] == '@') { //get localized text trap->SE_GetStringTextString(loc+1, loc, sizeof( loc ) ); } trap->S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); //Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); Com_sprintf(text, sizeof( text ), "%s^7<%s> ^%s%s", name, loc, color, message); CG_RemoveChatEscapeChar( text ); //Raz: Siege chat now uses the fancy new chatbox if ( cg_newChatbox.integer ) JP_ChatboxAdd( text, qfalse, "normal" ); else CG_ChatBox_AddString( text ); trap->Print( "*%s\n", text ); Q_StripColor( text ); CG_LogPrintf( cg.log.chat, va( "%s\n", text ) ); } return; } if ( !strcmp( cmd, "ltchat" ) ) { char name[MAX_STRING_CHARS]; char loc[MAX_STRING_CHARS]; char color[8]; char message[MAX_STRING_CHARS]; if (trap->Cmd_Argc() < 4) { return; } Q_strncpyz( name, CG_Argv( 1 ), sizeof( name ) ); Q_strncpyz( loc, CG_Argv( 2 ), sizeof( loc ) ); Q_strncpyz( color, CG_Argv( 3 ), sizeof( color ) ); Q_strncpyz( message, CG_Argv( 4 ), sizeof( message ) ); if (loc[0] == '@') { //get localized text trap->SE_GetStringTextString(loc+1, loc, sizeof( loc ) ); } trap->S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); //Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); Com_sprintf(text, sizeof( text ), "%s^7<%s> ^%s%s", name, loc, color, message); CG_RemoveChatEscapeChar( text ); if ( cg_newChatbox.integer ) JP_ChatboxAdd( text, qfalse, "team" ); else CG_ChatBox_AddString( text ); trap->Print( "*%s\n", text ); Q_StripColor( text ); CG_LogPrintf( cg.log.chat, va( "%s\n", text ) ); return; } if ( !strcmp( cmd, "scores" ) ) { CG_ParseScores(); return; } if ( !strcmp( cmd, "tinfo" ) ) { CG_ParseTeamInfo(); return; } if ( !strcmp( cmd, "map_restart" ) ) { CG_MapRestart(); return; } //Raz: Buffer overflow fix #if 0 if ( Q_stricmp (cmd, "remapShader") == 0 ) { if (trap->Cmd_Argc() == 4) { trap->R_RemapShader(CG_Argv(1), CG_Argv(2), CG_Argv(3)); } } #else if ( !Q_stricmp( cmd, "remapShader" ) ) { if ( trap->Cmd_Argc() == 4 ) { char shader1[MAX_QPATH]; char shader2[MAX_QPATH]; Q_strncpyz( shader1, CG_Argv( 1 ), sizeof( shader1 ) ); Q_strncpyz( shader2, CG_Argv( 2 ), sizeof( shader2 ) ); trap->R_RemapShader( shader1, shader2, CG_Argv( 3 ) ); return; } return; } #endif // loaddeferred can be both a servercmd and a consolecmd if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo CG_LoadDeferredPlayers(); return; } // clientLevelShot is sent before taking a special screenshot for // the menu system during development if ( !strcmp( cmd, "clientLevelShot" ) ) { cg.levelShot = qtrue; return; } trap->Print( "Unknown client game command: %s\n", cmd ); }
char *demoAutoFormat(const char* name) { const char *format; qboolean haveTag = qfalse; char outBuf[512]; int outIndex = 0; int outLeft = sizeof(outBuf) - 1; int t = 0; char timeStamps[MAX_QPATH] = ""; qtime_t ct; char playerName[MAX_QPATH], *mapName = COM_SkipPath(Info_ValueForKey((cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO]), "mapname")); Q_strncpyz(playerName, Info_ValueForKey((cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS+cl.snap.ps.clientNum]), "n"), sizeof(playerName)); if (cls.uag.newColors) Q_StripColorUAG(playerName); else Q_StripColor(playerName); Com_RealTime(&ct); format = cl_autoDemoFormat->string; if (!format || !format[0]) { if (!name || !name[0]) { format = "%t"; } else { format = "%n_%t"; } } while (*format && outLeft > 0) { if (haveTag) { char ch = *format++; haveTag = qfalse; switch (ch) { case 'd': //date Com_sprintf( outBuf + outIndex, outLeft, "%d-%02d-%02d-%02d%02d%02d", 1900+ct.tm_year, ct.tm_mon+1,ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec); outIndex += strlen( outBuf + outIndex ); break; case 'm': //map Com_sprintf( outBuf + outIndex, outLeft, mapName); outIndex += strlen( outBuf + outIndex ); break; case 'n': //custom demo name Com_sprintf( outBuf + outIndex, outLeft, name); outIndex += strlen( outBuf + outIndex ); break; case 'p': //current player name Com_sprintf( outBuf + outIndex, outLeft, playerName); outIndex += strlen( outBuf + outIndex ); break; case 't': //timestamp while (demo.record.timeStamps[t] && t < MAX_TIMESTAMPS) { int min = demo.record.timeStamps[t] / 60000; int sec = (demo.record.timeStamps[t] / 1000) % 60; if (t == 0) { Com_sprintf(timeStamps, sizeof(timeStamps), "%0.2d%0.2d", min, sec); } else { Com_sprintf(timeStamps, sizeof(timeStamps), "%s_%0.2d%0.2d", timeStamps, min, sec); } t++; } Com_sprintf( outBuf + outIndex, outLeft, timeStamps); outIndex += strlen( outBuf + outIndex ); break; case '%': outBuf[outIndex++] = '%'; break; default: continue; } outLeft = sizeof(outBuf) - outIndex - 1; continue; } if (*format == '%') { haveTag = qtrue; format++; continue; } outBuf[outIndex++] = *format++; outLeft = sizeof(outBuf) - outIndex - 1; } outBuf[ outIndex ] = 0; return va("%s", outBuf); }