// GPL License - see http://opensource.org/licenses/gpl-license.php // Copyright 2006 *nixCoders team - don't forget to credit us #include #include "eth.h" /* ============================== Some utils functions ============================== */ int getSpawntimer(qboolean enemySpawn) { int team = eth.clientInfo[eth.cg_snap->ps.clientNum].team; int limbotime = 0; // Reverse the value from clientinfo[myself].team to make the function return the spawn time of the other team if(enemySpawn == qtrue) { if (team == TEAM_AXIS) { team = TEAM_ALLIES; limbotime = eth.cg_bluelimbotime; } else if (team == TEAM_ALLIES) { team = TEAM_AXIS; limbotime = eth.cg_redlimbotime; } else return -1; } else { if (team == TEAM_AXIS) { limbotime = eth.cg_redlimbotime; } else if (team == TEAM_ALLIES) { limbotime = eth.cg_bluelimbotime; } else return -1; } // Sanity check if (limbotime == 0) { ethLog("warning: can't get spawntimer for team %i", team); return -1; } return (int)(1 + (limbotime - ((eth.cgs_aReinfOffset[team] + eth.cg_time - eth.cgs_levelStartTime) % limbotime)) * 0.001f); } int findSatchel() { int entityNum = 0; for (; entityNum < MAX_GENTITIES; entityNum++) { if ((eth.cg_entities[entityNum].currentState->weapon == WP_SATCHEL) && (eth.cg_entities[entityNum].currentState->clientNum == eth.cg_snap->ps.clientNum) && (!VectorCompare(eth.entities[entityNum].origin, vec3_origin))) return entityNum; } #ifdef ETH_DEBUG ethDebug("satchel cam: don't find satchel for %i", eth.cg_snap->ps.clientNum); #endif return -1; } qboolean isKeyActionDown(char *action) { int key1, key2; orig_syscall(CG_KEY_BINDINGTOKEYS, action, &key1, &key2); if (syscall_CG_Key_IsDown(key1) || syscall_CG_Key_IsDown(key2)) return qtrue; else return qfalse; } int getIdByName (const char *name, int len) { int i; if (!len) len = strlen(name); for (i=0; i < MAX_CLIENTS; i++) if (eth.clientInfo[i].infoValid && !strncmp(eth.clientInfo[i].name, name, len)) return i; return -1; } qboolean isVisible(vec3_t target) { trace_t trace; eth.CG_Trace(&trace, eth.cg_refdef.vieworg, NULL, NULL, target, eth.cg_snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_CORPSE); return (trace.fraction == 1.0f); } qboolean isPlayerVisible(vec3_t target, int player) { trace_t traceVisible; eth.CG_Trace(&traceVisible, eth.cg_refdef.vieworg, NULL, NULL, target, eth.cg_snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_CORPSE); trace_t tracePlayer; eth.CG_Trace(&tracePlayer, eth.cg_refdef.vieworg, NULL, NULL, target, eth.cg_snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_BODY); //printf("XXX: want %i got %i\n", player, tracePlayer.entityNum); return ((traceVisible.fraction == 1.0f) && (tracePlayer.entityNum == player)); } void ethLog(const char *format, ...) { printf("eth: "); va_list arglist; va_start(arglist, format); vprintf(format, arglist); va_end(arglist); printf("\n"); #ifdef ETH_DEBUG // If log file if (debugFile) { fprintf(debugFile, "log: "); va_list arglist; va_start(arglist, format); vfprintf(debugFile, format, arglist); va_end(arglist); fprintf(debugFile, "\n"); } #endif } #ifdef ETH_DEBUG FILE *debugFile = NULL; void ethDebug(const char *format, ...) { // If log file if (debugFile) { va_list arglist; va_start(arglist, format); vfprintf(debugFile, format, arglist); va_end(arglist); fprintf(debugFile, "\n"); } } #endif // ETH_DEBUG void fatalError(const char *msg) { char str[256]; snprintf(str, sizeof(str), "A fatal error has occured. You must restart the game.\n\nError: %s\n\n\n*nixCoders eth-v%s", msg, ETH_VERSION); orig_syscall(CG_ERROR, str); #ifdef ETH_DEBUG ethLog("fatal error: %s", msg); #endif } // Helper function for get ouput of a system command // This function return the first line of this command output char *getOutputSystemCommand(const char *command) { static char buf[256]; memset(buf, 0, sizeof(buf)); FILE *cmd = popen(command, "r"); int c; int count = 0; while (((c = getc(cmd)) != EOF) && (count < (sizeof(buf) - 1))) { if (c == '\n') break; buf[count++] = c; } pclose(cmd); return buf; } // If cgame is load, send a UI_PRINT message else just show a message at console, // WARNING ! use this function only when call from ui vmMain. ex: irc and game command #define MESSAGE_COLOR "^n" void gameMessage(qboolean forceConsole, char *format, ...) { char msg[MAX_SAY_TEXT]; memset(msg, 0, sizeof(msg)); char buffer[sizeof(msg)]; memset(buffer, 0, sizeof(buffer)); va_list arglist; va_start(arglist, format); vsnprintf(msg, sizeof msg, format, arglist); va_end(arglist); if (eth.hookLoad && !forceConsole) { snprintf(buffer, sizeof(buffer), "echo \"" MESSAGE_COLOR "%s\"\n", msg); orig_syscall(UI_CMD_EXECUTETEXT, EXEC_APPEND, buffer); } else { snprintf(buffer, sizeof(buffer), MESSAGE_COLOR "%s\n", msg); orig_syscall(UI_PRINT, buffer); } } void doAutoVote(char *str) { char *ptr = strstr(str, "^7 called a vote. Voting for: "); int id = getIdByName(str, ptr - str); // id not found if (id == -1) return; // who votes switch (eth.clientInfo[id].targetType) { case PLIST_FRIEND: syscall_CG_SendConsoleCommand("vote yes\n"); return; case PLIST_TEAMKILLER: syscall_CG_SendConsoleCommand("vote no\n"); return; default: break; } // Voter is not a friend/teamkiller ptr += strlen("^7 called a vote. Voting for: "); if (!strncmp(ptr, "KICK ", 5) || !strncmp(ptr, "MUTE ", 5)) { ptr += 5; id = getIdByName(ptr, strrchr(ptr, '\n') - ptr); // id not found if (id == -1) return; // vote against client if (id == eth.cg_clientNum) { syscall_CG_SendConsoleCommand("vote no\n"); return; } // who is voted against switch (eth.clientInfo[id].targetType) { case PLIST_FRIEND: syscall_CG_SendConsoleCommand("vote no\n"); return; case PLIST_TEAMKILLER: syscall_CG_SendConsoleCommand("vote yes\n"); return; default: break; } } } // Auto request medic #define TIME_BETWEEN_REQUEST 5000 void autoRequestMedic() { if (eth.cg_snap->ps.clientNum != eth.cg_clientNum) return; static int lastRequestTime = 0; if (lastRequestTime + TIME_BETWEEN_REQUEST > eth.cg_time) return; // If need revive if (eth.cg_entities[eth.cg_clientNum].currentState->eFlags & EF_DEAD) { int vsay = (int)(2.0f * (rand() / (RAND_MAX + 1.0f))); if (!vsay) syscall_CG_SendConsoleCommand("vsay_team Medic\n"); else syscall_CG_SendConsoleCommand("vsay_team FTReviveMe\n"); lastRequestTime = eth.cg_time; // If need health } else if (eth.cg_snap->ps.stats[STAT_HEALTH] < 40) { int vsay = (int)(2.0f * (rand() / (RAND_MAX + 1.0f))); if (!vsay) syscall_CG_SendConsoleCommand("vsay_team Medic\n"); else syscall_CG_SendConsoleCommand("vsay_team FTHealMe\n"); lastRequestTime = eth.cg_time; } } // Calc muzzle // kobj fixed the muzzle thing :D (Hooked server bullet_fire, and they match) void setCurrentMuzzle() { VectorCopy(eth.cg_refdef.vieworg, eth.muzzle); if(eth.cg_snap->ps.viewangles[PITCH] > 30 && (eth.cg_snap->ps.eFlags & EF_CROUCHING)) eth.muzzle[2] += 30.0 - eth.cg_snap->ps.viewheight; SnapVector( eth.muzzle ); } qboolean isAimbotWeapon(int weapon){ switch( weapon ){ case WP_AMMO: case WP_ARTY: case WP_MEDIC_SYRINGE: case WP_DYNAMITE: case WP_SMOKETRAIL: case WP_MAPMORTAR: case WP_MEDKIT: case WP_BINOCULARS: case WP_PLIERS: case WP_LANDMINE: case WP_SATCHEL: case WP_TRIPMINE: case WP_SMOKE_BOMB: case WP_MORTAR: case WP_MEDIC_ADRENALINE: return qfalse; default: return qtrue; } } /* ============================== Config stuff ============================== */ char *getConfigFilename() { // If config filename is set by enviromment var if (getenv("ETH_CONF_FILE")) return getenv("ETH_CONF_FILE"); static char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/%s", getenv("HOME"), ETH_CONFIG_FILE); return filename; } void readConfig() { FILE *file; // Init all user vars with the default value int count = 0; for (; count < VARS_TOTAL; count++) seth.value[count] = seth.vars[count].defaultValue; if ((file = fopen(getConfigFilename(), "rb")) == NULL) return; // Get config file line by line char line[1024]; while (fgets(line, sizeof(line) - 1, file) != 0) { char *sep = strrchr(line, '='); *sep = '\0'; // Separate name from value if( !sep ) fatalError("Config error. Check your config file!"); // Search this var int count = 0; if( !strcmp(line,"bnFormat") ) { strncpy(bnFormat, Q_ValidStr(sep+1), sizeof(ksFormat)); } else { for (; count < VARS_TOTAL; count++) { if (!seth.vars[count].cvarName) { ethLog("readConfig: error: VAR_%i undefine", count); } else if (!strcmp(line, seth.vars[count].cvarName)) { seth.value[count] = atof(sep + 1); break; } else if ((count + 1) == VARS_TOTAL) { ethLog("readConfig: don't know this var: [%s]", line); } if (count == VAR_CHUD) if (atoi(sep + 1)) syscall_CG_SendConsoleCommand(va("cg_draw2d %s\n", seth.value[count] ? "0" : "1")); } } } fclose(file); } void writeConfig() { FILE *file; if ((file = fopen(getConfigFilename(), "w")) == NULL) { ethLog("eth: can't write config file."); return; } int count = 0; fprintf(file,"ksFormat=%s\n",ksFormat); fprintf(file,"bnFormat=%s\n",bnFormat); for (; count < VARS_TOTAL; count++) { if (!seth.vars[count].cvarName) ethLog("writeConfig: error: VAR_%i undefine", count); else if (seth.value[count] == (float)(int)seth.value[count]) fprintf(file, "%s=%i\n", seth.vars[count].cvarName, (int)seth.value[count]); else fprintf(file, "%s=%.2f\n", seth.vars[count].cvarName, seth.value[count]); } fclose(file); } /* ============================== Console actions ============================== */ void initActions() { eth.actions[ACTION_ATTACK]= (ethAction_t){ 0, 0, "+attack; +moveleft; +moveright\n","-attack; -moveleft; -moveright\n" }; eth.actions[ACTION_BACKWARD] = (ethAction_t){ 0, 0, "+backward\n", "-backward\n" }; eth.actions[ACTION_BINDMOUSE1] = (ethAction_t){ 1, 1, "bind mouse1 +attack +\n", "unbind mouse1\n" }; eth.actions[ACTION_CROUCH] = (ethAction_t){ 0, 0, "+movedown\n", "-movedown\n" }; eth.actions[ACTION_JUMP] = (ethAction_t){ 0, 0, "+moveup\n", "-moveup\n" }; eth.actions[ACTION_PRONE] = (ethAction_t){ 0, 0, "+prone; -prone\n", "+moveup; -moveup\n" }; eth.actions[ACTION_RUN] = (ethAction_t){ 0, 0, "+sprint; +forward\n", "-sprint; -forward\n" }; eth.actions[ACTION_SCOREBOARD] = (ethAction_t){ 0, 0, "cg_draw2d 1; +scores\n", "-scores; cg_draw2d 0\n" }; eth.actions[ACTION_RELOAD] = (ethAction_t){ 0, 0, "+reload\n", "-reload\n" }; } // Set an action if not already set. void setAction(int action, int state) { if (state && !eth.actions[action].state) forceAction(action, state); else if (!state && eth.actions[action].state) forceAction(action, state); } // Use this with caution void forceAction(int action, int state) { if (state) { eth.actions[action].state = 1; syscall_CG_SendConsoleCommand(eth.actions[action].startAction); #ifdef ETH_DEBUG ethDebug("forceAction: %s", eth.actions[action].startAction); #endif } else { eth.actions[action].state = 0; syscall_CG_SendConsoleCommand(eth.actions[action].stopAction); #ifdef ETH_DEBUG ethDebug("forceAction: %s", eth.actions[action].stopAction); #endif } } void resetAllActions() { int action; for (action=0; action spreeLevelMax) level = spreeLevelMax; int levelSize = spreeLevels[level].end - spreeLevels[level].start; int sound = (int)((float)(levelSize + 1) * rand() / (RAND_MAX + 1.0f)); sound += spreeLevels[level].start; eth.spreelevel = sound; eth.startFadeTime = eth.cg_time; eth.s_level = level; orig_syscall(CG_S_STARTLOCALSOUND, eth.sounds[sound], CHAN_LOCAL_SOUND, 230); } } /* replaces tokens with correct value and returns pointer parsed string [c] - current spree count [v] - victim name [n] - clean victim name [t] - total kills [m] - double/triple/multikill msg [x] - Player XP [p] - Player name [M] - Mod name [h] - Player health [k] - Killer name [K] - Clean killer name [q] - amount of punkbuster screenshots requested */ char *Format(char *in){ char out[256]; memset(out, 0, sizeof(out)); int a, b, len = strlen(in); for (a = 0, b = 0; a < len; a++) { if ((a <= len-2) && (in[a] == '[' && in[a+2] == ']')) { switch (in[a+1]) { case 'v': strncat(out, eth.VictimName, sizeof(out)); break; case 'n': strncat(out, Q_CleanStr(eth.VictimName), sizeof(out)); break; case 't': strncat(out, va("%i", eth.killCount), sizeof(out)); break; case 'x': strncat(out, va("%i", eth.cg_snap->ps.stats[STAT_XP]), sizeof(out)); break; case 'q': strncat(out, va("%i", eth.pbss), sizeof(out)); break; case 'p': strncat(out, eth.clientInfo[eth.cg_clientNum].name, sizeof(out)); break; case 'M': { char gameMod[20]; syscall_CG_Cvar_VariableStringBuffer("fs_game", gameMod, sizeof(gameMod)); strncat(out, gameMod, sizeof(out)); break; } case 'k': strncat(out, eth.KillerName, sizeof(out)); break; case 'K': { char *c = strdup(eth.KillerName); strncat(out, Q_CleanStr(c) , sizeof(out)); free(c); break; } case 'h': strncat(out, va("%i", eth.cg_snap->ps.stats[STAT_HEALTH]), sizeof(out)); break; case 'c': strncat(out, va("%i", eth.killCountNoDeath), sizeof(out)); break; case '1': { char *multikillmsg ; int randmsg = rand() % 3; if (eth.killSpreeCount == 2) { if (!randmsg) multikillmsg = " ^1*** DOUBLEKILL***^7"; else if (randmsg == 1) multikillmsg = " ^1*** DOUBLEKILL***^7"; else multikillmsg = " ^1*** DOUBLEKILL***^7"; } else if (eth.killSpreeCount == 3) { if (!randmsg) multikillmsg = " ^1*** MULTIKILL***^7"; else if (randmsg == 1) multikillmsg = " ^1*** MULTIKILL***^7"; else multikillmsg = " ^1*** MULTIKILL***^7"; } else if (eth.killSpreeCount == 4) { if (!randmsg) multikillmsg = " ^1*** ULTRAKILL***^7"; else if (randmsg == 1) multikillmsg = " ^1*** ULTRAKILL***^7"; else multikillmsg = " ^1*** ULTRAKILL***^7"; } else if (eth.killSpreeCount > 4) { if (!randmsg) multikillmsg = " ^1*** MONSTERKILL***^7"; else if (randmsg == 1) multikillmsg = " ^1*** HOLY SHIT ***^7"; else multikillmsg = " ^1*** MONSTERKILL***^7"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "^2%s ^7was owned %s ", eth.VictimName, multikillmsg); break; } case '2': { char *multikillmsg; int randmsg = rand() % 3; if (eth.killSpreeCount == 2) { if (!randmsg) multikillmsg = " ^1--> ^3D^9ouble ^3K^9ill^3!"; else if (randmsg == 1) multikillmsg = " ^1--> ^3D^9ouble ^3K^9ill^3!"; else multikillmsg = " ^1--> ^3D^9ouble ^3K^9ill^3!"; } else if (eth.killSpreeCount == 3) { if (!randmsg) multikillmsg = " ^1--> ^3M^9ulti ^3K^9ill^3!"; else if (randmsg == 1) multikillmsg = " ^1--> ^3M^9ulti ^3K^9ill^3!"; else multikillmsg = " ^1--> ^3M^9ulti ^3K^9ill^3!"; } else if (eth.killSpreeCount == 4) { if (!randmsg) multikillmsg = " ^1--> ^3U^9ltra ^3K^9ill^3!"; else if (randmsg == 1) multikillmsg =" ^1--> ^3U^9ltra ^3K^9ill^3!"; else multikillmsg = " ^1--> ^3U^9ltra ^3K^9ill^3!"; } else if (eth.killSpreeCount > 4) { if (!randmsg) multikillmsg = " ^1--> ^3M^9onster ^3K^9ill^3!"; else if (randmsg == 1) multikillmsg = " ^1--> ^3H^9oly ^3Shit^1!"; else multikillmsg = " ^1--> ^3M^9onster ^3K^9ill^3!"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "^2%s ^3W^9as ^3O^9wned^3! %s ", eth.VictimName, multikillmsg); break; } case '3': { char *multikillmsg; int randmsg = rand() % 3; if (eth.killSpreeCount == 2) { if (!randmsg) multikillmsg = " ^7::: ^2Doublekill ^7:::"; else if (randmsg == 1) multikillmsg = " ^7::: ^2Doublekill ^7:::"; else multikillmsg = " ^7::: ^2Doublekill ^7:::"; } else if (eth.killSpreeCount == 3) { if (!randmsg) multikillmsg = " ^7::: ^2Multikill ^7:::"; else if (randmsg == 1) multikillmsg = " ^7::: ^2Multikill ^7:::"; else multikillmsg = " ^7::: ^2Multikill ^7:::"; } else if (eth.killSpreeCount == 4) { if (!randmsg) multikillmsg = " ^7::: ^2Ultrakill ^7:::"; else if (randmsg == 1) multikillmsg = " ^7::: ^2Ultrakill ^7:::"; else multikillmsg = " ^7::: ^2Ultrakill ^7:::"; } else if (eth.killSpreeCount > 4) { if (!randmsg) multikillmsg = " ^7::: ^2Monsterkill ^7:::"; else if (randmsg == 1) multikillmsg = " ^7::: ^2Monsterkill ^7:::"; else multikillmsg = " ^7::: ^2Monsterkill ^7:::"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "%s ", multikillmsg); break; } case 'e': { char *msg; if (eth.killCountNoDeath == 10) { msg = "^7... is ^/tied for the lead! ^%(10 frags in a row)"; } else if (eth.killCountNoDeath == 15) { msg = "^7... has ^3taken the lead! ^%(15 frags in a row)"; } else if (eth.killCountNoDeath == 20) { msg = "^7... is on a ^3KILLING SPREE!!! ^%(20 frags in a row)"; } else if (eth.killCountNoDeath == 25) { msg = "^7... is ^/DOMINATING!!! ^%(25 frags in a row)"; } else if (eth.killCountNoDeath == 30) { msg = "^7... is on a ^/RAMPAGE!!! ^%(30 frags in a row)"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "%s ", msg); break; } case '6': { char *multikillmsg; int randmsg = rand() % 3; if (eth.killSpreeCount == 2) { if (!randmsg) multikillmsg = "^3!!^1Doublekill^3!!"; else if (randmsg == 1) multikillmsg = "^3!!^1Doublekill^3!!"; else multikillmsg = "^3!!^1Doublekill^3!!"; } else if (eth.killSpreeCount == 3) { if (!randmsg) multikillmsg = "^3!!!^1Multikill^3!!!"; else if (randmsg == 1) multikillmsg = "^3!!!^1Triple Kill^3!!!"; else multikillmsg = "^3!!!^1Multikill^3!!!"; } else if (eth.killSpreeCount == 4) { if (!randmsg) multikillmsg = "^3!!!^1Ultra Kill^3!!!"; else if (randmsg == 1) multikillmsg = "^3!!!^1Dominating^3!!!"; else multikillmsg = "^3!!!^1Ultra Kill^3!!!"; } else if (eth.killSpreeCount > 5) { if (!randmsg) multikillmsg = "^3!!!^1Monsterkill^3!!!"; else if (randmsg == 1) multikillmsg = "^3!!!^1Holy Shit^3!!!"; else multikillmsg = "^3!!!^1Wicked Sick^3!!!"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "%s ", multikillmsg); break; } case 'R': { char *msg; if (eth.killCountNoDeath == 10) { msg = "^7is on a ^1KILLING SPREE!!! ^3(10 frags in a row)"; } else if (eth.killCountNoDeath == 15) { msg = "^7is ^1DOMINATING!!! ^3(15 frags in a row)"; } else if (eth.killCountNoDeath == 20) { msg = "^7is on a ^1RAMPAGE!!! ^3(20 frags in a row)"; } else if (eth.killCountNoDeath == 25) { msg = "^7is ^1UNSTOPPABLE!!! ^3(25 frags in a row)"; } else if (eth.killCountNoDeath == 30) { msg = "^7is ^1WICKED SICK!!! ^3(30 frags in a row)"; } else if (eth.killCountNoDeath == 35) { msg = "^7is on a ^1MEGA KILLINGSPREE!!! ^3(35 frags in a row)"; } else if (eth.killCountNoDeath == 40) { msg = "^7is ^1OMFGHAXOR!!! ^3(40 frags in a row)"; } else break; if (eth.killCountNoDeath >= 2) sprintf(out, "%s ", msg); break; } case '5': { char *multikillmsg; int randmsg = rand() % 3; if (eth.killSpreeCount == 2) { if (!randmsg) multikillmsg = " ^1-> ^7doubleLEAK!"; else if (randmsg == 1) multikillmsg = " ^1-> ^7doubleLEAK!"; else multikillmsg = " ^1-> ^7doubleLEAK!"; } else if (eth.killSpreeCount == 3) { if (!randmsg) multikillmsg = " ^1-> ^7multiLEAK!"; else if (randmsg == 1) multikillmsg = " ^1-> ^7multiLEAK!"; else multikillmsg = " ^1-> ^7multiLEAK!"; } else if (eth.killSpreeCount == 4) { if (!randmsg) multikillmsg = " ^1-> ^7ultraLEAK!"; else if (randmsg == 1) multikillmsg = " ^1-> ^7ultraLEAK!"; else multikillmsg = " ^1-> ^7ultraLEAK!"; } else if (eth.killSpreeCount > 4) { if (!randmsg) multikillmsg = " ^1-> ^7monsterLEAK!"; else if (randmsg == 1) multikillmsg = " ^1-> ^7Holy Shit!!!!!LEAK"; else multikillmsg = " ^1-> ^7monsterLEAK!"; } else break; if (eth.killSpreeCount >= 2) sprintf(out, "^2%s ^7was leaked! %s ", eth.VictimName, multikillmsg); break; } default: break; } a += 2; } else out[b] = in[a]; b = strlen(out); } strncpy(in,out,sizeof(out)); return in; } //tes: once per command call int isCommandTime(void) { static int lastTimeC; if(seth.value[VAR_SNAPDELAY] != 0) { if(lastTimeC + (int)seth.value[VAR_SNAPDELAY] > (eth.cg_time )) return 0; lastTimeC = eth.cg_time; return 1; } // tes: so if set to 0 then we do it like this: // count time delay for max commands we can send between snapshots // this is strictly ping based and seems to be solution i search for :) if((lastTimeC + (eth.cg_snap->ping/(CMD_BACKUP -1))) <= (eth.cg_time)){ lastTimeC = eth.cg_time; return 1; } return 0; } // Customizable spam void killSpam() { char msg[256]; char send[256]; strncpy(msg,ksFormat,sizeof(msg)); snprintf(send, sizeof(send), "say \"%s\"\n", Format(msg)); syscall_CG_SendConsoleCommand(send); } void timenudge(int nTime) { char send[256]; snprintf(send, sizeof(send), "cl_timenudge %d\n", nTime); syscall_CG_SendConsoleCommand(send); } // Auto demo record void autoRecord() { #define TMP_FILE_NAME "demo_in_progress" static qboolean demoState = qfalse; static int stateTime ; int ethRate; // Speed return if we don't want record demo if (!demoState && !seth.value[VAR_RECDEMO]) return; if ((eth.cg_snap->ps.eFlags != EF_DEAD) && (eth.cg_snap->ps.clientNum == eth.cg_clientNum) && (eth.clientInfo[eth.cg_clientNum].team != TEAM_SPECTATOR) && (eth.cg_snap->ps.stats[STAT_HEALTH] > 0) && (eth.cg_snap->ps.pm_flags != PMF_FOLLOW) && seth.value[VAR_RECDEMO] && !demoState) { stateTime=0 ; // FIXME: check if a tmp demo file already exist syscall_CG_SendConsoleCommand("record " TMP_FILE_NAME "\n"); stateTime = eth.cg_time; #ifdef ETH_DEBUG ethDebug("demo: start"); #endif demoState = qtrue; } else if (((eth.cg_snap->ps.eFlags == EF_DEAD) || (eth.cg_snap->ps.clientNum != eth.cg_clientNum) || (eth.clientInfo[eth.cg_clientNum].team == TEAM_SPECTATOR) || (eth.cg_snap->ps.stats[STAT_HEALTH] <= 0) || (eth.cg_snap->ps.pm_flags == PMF_FOLLOW) || (!seth.value[VAR_RECDEMO])) && demoState) { char buffFrom[MAX_OSPATH]; char buffTo[MAX_OSPATH]; // Get fsgame char fsGame[MAX_QPATH]; syscall_CG_Cvar_VariableStringBuffer("fs_game", fsGame, sizeof(fsGame)); // Get current time time_t ethTime = time(NULL); struct tm *localTime = localtime(ðTime); orig_Cbuf_ExecuteText(EXEC_NOW, "stoprecord\n"); stateTime = ((eth.cg_time - stateTime)/1000) ; ethRate=(int)((((float)eth.autoDemoKillCount/(float)stateTime)*100.0f)/(float)(0.2)) ; #ifdef ETH_DEBUG ethDebug("demo: final stateTime:[%i]", stateTime) ; ethDebug("demo: kill acc:[%i]",ethRate); ethDebug("demo: stop"); #endif // buffForm = /homepath/fsgame/ syscall_CG_Cvar_VariableStringBuffer("fs_homepath", buffFrom, sizeof(buffFrom)); sprintf(buffFrom, "%s/%s/demos/", buffFrom, fsGame); strncpy(buffTo, buffFrom, sizeof(buffFrom)); // buffForm = /homepath/fsgame/demos/demoinprogress strcat(buffFrom, TMP_FILE_NAME ".dm_"); // Contruct final file name, buffTo = /homepath/fsgame/demo/aaaa_mm_dd_hhmmss_mod_map_killcount sprintf(buffTo,"%s%i-%.2i-%.2i-%.2i%.2i%.2i_%s_%s_%ikills_%isec_%irate.dm_", buffTo, localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday, localTime->tm_hour, localTime->tm_min, localTime->tm_sec, fsGame, eth_Info_ValueForKey(eth.cgs_gameState->stringData + eth.cgs_gameState->stringOffsets[CS_SERVERINFO], "mapname"), eth.autoDemoKillCount, stateTime, ethRate); // Version of the demo if (!strcmp(sethET->version, "2.55")){ strcat(buffFrom, "82"); strcat(buffTo, "82"); } else if(!strcmp(sethET->version, "2.56")){ strcat(buffFrom, "83"); strcat(buffTo, "83"); } else { strcat(buffFrom, "84"); strcat(buffTo, "84"); } #ifdef ETH_DEBUG ethDebug("demo: got %i kills, need %i kills", eth.autoDemoKillCount, (int)seth.value[VAR_RECDEMO]); #endif // If we more than kills threshold then rename the demo if (eth.autoDemoKillCount >= seth.value[VAR_RECDEMO]) { #ifdef ETH_DEBUG ethDebug("demo: move [%s] to [%s]", buffFrom, buffTo); #endif rename(buffFrom, buffTo); // Else delete it } else { #ifdef ETH_DEBUG ethDebug("demo: delete [%s]", buffFrom, buffTo); #endif unlink(buffFrom); } eth.autoDemoKillCount = 0; demoState = qfalse; } } /* ============================== et guid ============================== */ // Init cl_guid by environnement var void loadCL_GUID(void) { char *cl_guid = getenv("CLGUID"); if (cl_guid) { syscall_CG_Cvar_Set("cl_guid", cl_guid); // Delete env var so cl_guid is set once, and not each cg_init unsetenv("CLGUID"); } } void doMusicSpam() { static char oldTitle[MAX_STRING_CHARS]; static qboolean firstTime = qtrue; char *artist,*currentTime,*totalTime,*title; artist=currentTime=totalTime=title=NULL; if( firstTime ){ oldTitle[0] = '\0'; firstTime = qfalse; return; } if( seth.value[VAR_MUSICSPAM]==1 ) title = strdup(getOutputSystemCommand("dcop amarok player title")); else if (seth.value[VAR_MUSICSPAM]==2) title = strdup(getOutputSystemCommand("xmmsctrl print %T")); else return; if( strcmp(title,oldTitle) ){ //new song char msg[MAX_STRING_CHARS]; strncpy(oldTitle,title,MAX_STRING_CHARS); if( seth.value[VAR_MUSICSPAM]==1 ){ artist = strdup(getOutputSystemCommand("dcop amarok player artist")); currentTime = strdup(getOutputSystemCommand("dcop amarok player currentTime")); totalTime = strdup(getOutputSystemCommand("dcop amarok player totalTime")); } else if( seth.value[VAR_MUSICSPAM]==2 ) { artist = NULL; // no artist print in xmmsctrl?? wtf? currentTime = strdup(getOutputSystemCommand("xmmsctrl print %m")); totalTime = strdup(getOutputSystemCommand("xmmsctrl print %M")); } if( artist ){ sprintf(msg,"say \"^oPlaying ^0[^w%s - %s^0]^*-^0[^w%s/%s^0]\"\n", artist, title, currentTime, totalTime); free(artist); } else sprintf(msg,"say \"^oPlaying ^0[^w%s^0]^*-^0[^w%s/%s^0]\"\n", title, currentTime, totalTime); syscall_CG_SendConsoleCommand(msg); free(currentTime); free(totalTime); } free(title); }