// GPL License - see http://opensource.org/licenses/gpl-license.php // Copyright 2006 *nixCoders team - don't forget to credit us /* ============================== All game functions hooked for get information from it. ============================== */ #include #include "eth.h" void eth_CG_R_AddRefEntityToScene(refEntity_t *refEnt) { ethEntity_t* entity = ð.entities[refEnt->entityNum]; int entityNum = refEnt->entityNum; trace_t trace; // Backup refEntity for spycam memcpy(ð.refEntities[eth.refEntitiesCount++], refEnt, sizeof(refEntity_t)); if ((entityNum < MAX_CLIENTS) && (eth.cg_entities[entityNum].currentState->eType == ET_PLAYER) && eth.clientInfo[entityNum].infoValid && (eth.cg_clientNum != entityNum)) { entity->isValid = qtrue; if ((refEnt->hModel == eth.hHead) || (refEnt->hModel == eth.hGlasses)) { // Skip already define head entity (hud head) if (!VectorCompare(vec3_origin, entity->head)) return; // Backup head origin VectorCopy(refEnt->origin, entity->head); // Add some vector Z for better display of esp vec3_t tmpVector; VectorCopy(entity->head, tmpVector); tmpVector[ROLL] += 20.0f; entity->isInScreen = worldToScreen(tmpVector, &entity->screenX, &entity->screenY); // Backup head axis for mortar trace memcpy(entity->headAxis, refEnt->axis, sizeof(vec3_t) * 3); // Apply vecz doVecZ(entityNum); // Prediction #ifdef ETH_DEBUG if (!seth.value[VAR_PREDICT_STATS]) #endif doPrediction(entityNum); // Draw a rail trail to see where the player look if (seth.value[VAR_RAILAXIS]) { vec3_t forward; VectorMA(entity->head, 64, refEnt->axis[0], forward); eth.CG_RailTrail2(NULL, entity->head, forward); } // If head visible if (isVisible(entity->head)) { entity->isVisible = qtrue; entity->isHeadVisible = qtrue; } // Pig head for enemy if (seth.value[VAR_PIGHEAD] && IS_PLAYER_ENEMY(entityNum)) { refEnt->hModel = eth.pigHeadModel; refEnt->customSkin = eth.pigHeadSkin; // Chams } else { if (seth.value[VAR_CHAMS] && !seth.value[VAR_PIGHEAD] && (seth.value[VAR_CHAMS] != CHAM_GLOWONLY)) { addChams(refEnt, entity->isVisible); } } // If body } else if (refEnt->torsoFrameModel) { // Backup bodyRefEnt for tag grabbing memcpy(ð.cg_entities[entityNum].pe_bodyRefEnt, refEnt, sizeof(refEntity_t)); // Find a visible body parts vec3_t target; if (getVisibleModelBodyTag(entityNum, &target)) { VectorCopy(target, entity->bodyPart); entity->isVisible = qtrue; } // Chams if (seth.value[VAR_CHAMS]) addChams(refEnt, entity->isVisible); // Not body or head } else return; } else if (IS_MISSILE(entityNum)) { entity->isValid = qtrue; // If visible eth.CG_Trace(&trace, eth.cg_refdef.vieworg, NULL, NULL, refEnt->origin, eth.cg_snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_CORPSE); if (trace.fraction == 1.0f) entity->isVisible = qtrue; // Chams if (seth.value[VAR_CHAMS]) addChams(refEnt, (trace.fraction == 1.0f)); // Add rail trail here so it can have wallhack too } else if (refEnt->reType == RT_RAIL_CORE) { // Not player or missile } else return; // Wallhack if (seth.value[VAR_WALLHACK]) refEnt->renderfx |= RF_DEPTHHACK | RF_NOSHADOW; } void eth_CG_S_UpdateEntityPosition(int entityNum, const vec3_t origin) { ethEntity_t* entity = ð.entities[entityNum]; entity->isValid = qtrue; if (IS_PLAYER_VALID(entityNum) || IS_MISSILE(entityNum)) { VectorCopy(origin, entity->origin); entity->distance = VectorDistance(eth.cg_refdef.vieworg, entity->origin); // isInScreen is define below for players if (entityNum > MAX_CLIENTS) entity->isInScreen = worldToScreen(entity->origin, &entity->screenX, &entity->screenY); addEspColors(entityNum, entity->isVisible); } } void eth_CG_DrawActiveFrame(void) { // Don't draw stuff in intermission if (eth.cgs_gamestate != GS_INTERMISSION) { setCurrentMuzzle(); drawStats(); // Set esp colors from vars setColors(); #ifdef ETH_DEBUG // Draw debugview if (seth.value[VAR_MEMDUMP]) drawMemDump(getVarOffset(seth.value[VAR_MEMDUMP]) + (eth.offsetMul * 200) + (eth.offsetSub * 20)); if (seth.value[VAR_PREDICT_STATS]) doPredictionStats(); #endif // Don't draw eth's visuals while drawing scoreboard (TAB) // it's a big mess otherwise qboolean drawEthVisuals = qtrue; if (isKeyActionDown("+scores")) { drawEthVisuals = qfalse; setAction(ACTION_SCOREBOARD, 1); } else if (seth.value[VAR_CHUD]) { setAction(ACTION_SCOREBOARD, 0); } if (!eth.demoPlayback) { if (seth.value[VAR_REQUEST_MEDIC] && (eth.mod->type != MOD_TCE)) autoRequestMedic(); // Auto demo record autoRecord(); // Autoshoot if (seth.value[VAR_AUTOSHOOT]) setAction(ACTION_BINDMOUSE1, qfalse); else setAction(ACTION_BINDMOUSE1, qtrue); // Medicbot if (seth.value[VAR_MEDICBOT]) doMedicBot(); // Random name changer if (seth.value[VAR_RANDOMNAME]) { // If error stop it if (!setRandomName()) seth.value[VAR_RANDOMNAME] = qfalse; } // Do aimbot doAimbot(); } if (!eth.demoPlayback && drawEthVisuals) { // These funcs are not needed when watching a demo // Draw spectators if (seth.value[VAR_SPEC] && (eth.cg_snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR)) { getSpectators(); drawSpectators(); } // Draw irc stuff drawIrcChat(); if (seth.value[VAR_IRC]) { if (seth.value[VAR_IRC_FT]) drawIrcFireteam(); if (seth.value[VAR_IRC_TOPIC] || seth.value[VAR_IRC_INVITE]) drawIrcTopic(); } // Teamkillers / Friends add/remove list if (eth.isPlistOpen) { drawPlayerList(); // Get mouse/key events orig_syscall(CG_KEY_SETCATCHER, KEYCATCH_UI | orig_syscall(CG_KEY_GETCATCHER)); } // Referee counter if (seth.value[VAR_REFLIST]) drawReferees(); } if (drawEthVisuals) { // Custom HUDs if (seth.value[VAR_CHUD] == HUD_1) drawCustomHud(); else if (seth.value[VAR_CHUD] == HUD_2) drawETHhud(); // Draw right spawntimer if (seth.value[VAR_SPAWNTIMER] && !seth.value[VAR_CHUD]) // Don't need 2 spawntimers at the same time drawSpawnTimerRight(); // Draw advert if (seth.value[VAR_ADVERT]) drawAdvert(); // Draw players infos drawEspEntities(); // Draw radar switch ((int)seth.value[VAR_RADAR]) { case 1: drawRadar(200); break; case 2: drawRadar(150); break; case 3: drawRadar(100); break; case 4: drawRadar(50); break; case 5: drawRadarNg(150); break; case 6: drawRadarNg(100); break; case 7: drawRadarNg(50); break; default: break; } // Crosshair if (seth.value[VAR_CROSSHAIR]) drawCrosshair(); } } if (eth.pointer) orig_syscall(CG_KEY_SETCATCHER, KEYCATCH_UI | orig_syscall(CG_KEY_GETCATCHER)); if (eth.isMenuOpen) { drawMenu(); // Get mouse/key events orig_syscall(CG_KEY_SETCATCHER, KEYCATCH_UI | orig_syscall(CG_KEY_GETCATCHER)); } // Remove spectator locking if (seth.value[VAR_SPECLOCK]) eth.cg_snap->ps.powerups[PW_BLACKOUT] = 0; } // Check if the scene is the mainview if ((refdef->x == 0) || (refdef->x == 1)) { // Some mods use 0 or 1 for x // Check for background scene (only some tce version use that) if ((eth.mod->type == MOD_TCE) && (refdef->rdflags & RDF_SKYBOXPORTAL) && (eth.mod->crc32 == 0x965ad597)) return qtrue; // Copy main refdef memcpy(ð.cg_refdef, refdef, sizeof(refdef_t)); vectoangles(eth.cg_refdef.viewaxis[0], eth.cg_refdefViewAngles); if (seth.value[VAR_WEAPZOOM] && (eth.mod->type != MOD_TCE)) { switch(eth.cg_snap->ps.weapon) { case WP_FG42SCOPE: case WP_GARAND_SCOPE: case WP_K43_SCOPE: // fov_x - Get from cg_fov cvar syscall_CG_Cvar_VariableStringBuffer("cg_fov", fov, sizeof(fov)); refdef->fov_x = atof(fov); // fov_y - Algo taken from cg_view.c line 961 x = refdef->width / tan(refdef->fov_x / 360 * M_PI); refdef->fov_y = atan2(refdef->height, x); refdef->fov_y *= 360 / M_PI; break; case WP_MOBILE_MG42_SET: // fov_x - Get from cg_fov cvar syscall_CG_Cvar_VariableStringBuffer("cg_fov", fov, sizeof(fov)); refdef->fov_x = atof(fov); // fov_y - Algo taken from cg_view.c line 961 x = refdef->width / tan(refdef->fov_x / 360 * M_PI); refdef->fov_y = atan2(refdef->height, x); refdef->fov_y *= 360 / M_PI; break; default: break; } } else if (eth.mod->type == MOD_TCE) { char fov[8]; syscall_CG_Cvar_VariableStringBuffer("cg_fov", fov, sizeof(fov)); int fov_val = atoi(fov); refdef->fov_x = fov_val; refdef->fov_y = fov_val; } // Call original function orig_syscall(CG_R_RENDERSCENE, refdef); // Weapons are different in tce if (eth.mod->type != MOD_TCE) { // Weapons are different in tce if (eth.mod->type != MOD_TCE) { // Weapons spy cam switch (eth.cg_entities[eth.cg_snap->ps.clientNum].currentState->weapon) { case WP_LUGER: case WP_SILENCER: case WP_AKIMBO_LUGER: case WP_AKIMBO_SILENCEDLUGER: case WP_COLT: case WP_SILENCED_COLT: case WP_AKIMBO_COLT: case WP_AKIMBO_SILENCEDCOLT: case WP_MP40: case WP_THOMPSON: case WP_STEN: case WP_GARAND: case WP_FG42: case WP_FG42SCOPE: case WP_KAR98: case WP_CARBINE: case WP_MOBILE_MG42: case WP_MOBILE_MG42_SET: case WP_K43: case WP_GARAND_SCOPE: case WP_K43_SCOPE; if (seth.value[VAR_TARGCAM]) drawTargCam(); break; case WP_MORTAR_SET: if (seth.value[VAR_MORTARCAM]) drawMortarCam(); break; case WP_PANZERFAUST: if (seth.value[VAR_PANZERCAM]) drawPanzerCam(); break; case WP_SATCHEL_DET: if (seth.value[VAR_SATCHELCAM]) drawSatchelCam(); break; case WP_GPG40: case WP_M7: if (seth.value[VAR_RIFLECAM]) drawRiffleCam(); break; default: break; } } if (seth.value[VAR_MIRRORCAM]) drawMirrorCam(); return qfalse; } return qtrue; } void eth_CG_Init(void) { loadCL_GUID(); initHUD(); srand(time(NULL)); initActions(); // Init stats eth.lastKillTime = 0; eth.firstKillSpreeTime = 0; #ifdef ETH_DEBUG // Init debug view vars eth.offsetSub = 0; eth.offsetMul = 0; #endif // Init eth medias registerEthMedias(); //syscall_CG_S_StartLocalSound(eth.sounds[SOUND_HUMILIATION], CHAN_AUTO); // TODO: not work ??? wtf ? initActions(); resetAllActions(); // If we do \disconnect and then \connect without quitting the game, update our buddy slot ircCGinit(); } void eth_CG_Shutdown(void) { setAction(ACTION_BINDMOUSE1, 1); blockMouse(qfalse); // To avoid sensitivity 0 } // This function was hook only to force sniper view void eth_CG_FinishWeaponChange(int lastweap, int newweap) { qboolean callOriginal = qfalse; if (!((lastweap == WP_K43_SCOPE && newweap == WP_K43) || (lastweap == WP_GARAND_SCOPE && newweap == WP_GARAND) || (lastweap == WP_FG42SCOPE && newweap == WP_FG42))) callOriginal = qtrue; int weapon = lastweap; switch (weapon) { case WP_K43_SCOPE: weapon = WP_K43; break; case WP_GARAND_SCOPE: weapon = WP_GARAND; break; case WP_FG42SCOPE: weapon = WP_FG42; break; default: break; } if (eth.cg_snap->ps.ammoclip[weapon] == 0) callOriginal = qtrue; if (isKeyActionDown("+reload") || isKeyActionDown("weapalt")) callOriginal = qtrue; if (callOriginal) eth.CG_FinishWeaponChange(lastweap, newweap); } // Hooked for catching kills void eth_CG_EntityEvent(centity_t *cent, vec3_t position) { entityState_t *es = ¢->currentState;; int event = es->event & ~EV_EVENT_BITS; switch (event) { case EV_OBITUARY: // Don't count kills in warmup. if (eth.cgs_gamestate != GS_PLAYING) break; // For now this way, report if it doesen't work on some mods int target, attacker; if (eth.mod->type == MOD_ETPRO) { target = es->time; attacker = es->time2; } else { target = es->otherEntityNum; attacker = es->otherEntityNum2; } // If we do a selfkill or someone kills us, reset killing spree if (target == eth.cg_clientNum) { eth.killCountNoDeath = 0; eth.killSpreeCount = 0; break; // Increase killcount only if we're the attacker and if we killed a player from the opposite team } else if (attacker == eth.cg_clientNum && eth.clientInfo[target].team != eth.clientInfo[eth.cg_clientNum].team) { strncpy(eth.VictimName, eth.clientInfo[target].name, sizeof(eth.VictimName)); eth.killCount++; eth.killCountNoDeath++; eth.autoDemoKillCount++; // Backup killcount for auto-record demo // If not a killing spree if ((eth.cg_time - eth.lastKillTime) > (SPREE_TIME * 1000)) { eth.firstKillSpreeTime = eth.cg_time; eth.killSpreeCount = 1; } else { eth.killSpreeCount++; } eth.lastKillTime = eth.cg_time; if (eth.killSpreeCount > 1) playSpreeSound(); if (seth.value[VAR_KILLSPAM]) killSpam(); } break; default: break; } eth.CG_EntityEvent(cent, position); } // Kick some recoil void eth_CG_DamageFeedback(int yawByte, int pitchByte, int damage) {} void eth_CG_WeaponFireRecoil(int weapon) {} /* ============================== cvars unlocker ============================== */ cvar_t *eth_Cvar_Set2(const char *var_name, const char *value, qboolean force) { #ifdef ETH_DEBUG ethDebug("cvar: [%s] forced to [%s]", var_name, value); #endif return orig_Cvar_Set2(var_name, value, qtrue); }