rendered paste body// Copyright 2006 *nixCoders team - don't forget to credit us
/*
==============================
All game functions hooked for get information from it.
==============================
*/
#include <sys/resource.h>
#include "eth.h"
//tes: this prediction uses engine of game + own catched experience shit etc.
int doPredCalc(vec3_t base_orig,int player,int future) {
float matrix[3][4];
float bounds[3][2];
int retval;
trajectory_t tr_tmp;
int delta_time;
int eFlags = eth.cg_entities[player].currentState->eFlags;
vec3_t o_tmp;
float speedscale;
if(future!=0) {
// tes: useles so commented
// if(lastTime == eth.cg_time)
// return 0;
// lastTime = eth.cg_time;
// } else {
// backup original trPos in case of prediction simulation
VectorCopy(history[player][0].trPos,o_tmp);
VectorCopy(base_orig,history[player][0].trPos);
}
tr_tmp.trTime = eth.cg_snap->serverTime + future;
VectorCopy(history[player][0].trPos, tr_tmp.trBase);
VectorCopy(history[player][0].trDelta, tr_tmp.trDelta);
//low ping users do not need prediction > 1
float f = (float)( eth.cg_time - history[player][1].t ) / ( history[player][0].t - history[player][1].t );
if (seth.value[VAR_INTERPOLATE] == qtrue)
delta_time = (eth.cg_snap->ping + f) / (CMD_BACKUP+1);
else
delta_time = eth.cg_snap->ping / (CMD_BACKUP+1);
// ^^ powa it is!
delta_time += seth.value[VAR_NUDGEHACK];
// but i comment it out need to be revised
// if(delta_time < 1) {
// if(lastTime > 0 && future !=0)
// delta_time = eth.cg_time - lastTime;
// else delta_time = 0;
// }
speedscale = 1.5;
tr_tmp.trDuration = delta_time;
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
// check for bird
if(eth.cg_entities[player].currentState->groundEntityNum == -1) {
tr_tmp.trType = TR_GRAVITY;
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
eth_BG_EvaluateTrajectoryDelta(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
}/*else{
tr_tmp.trType = TR_GRAVITY_FLOAT;
eth_BG_EvaluateTrajectoryDelta(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
}
*/
VectorCopy(history[player][0].prPos,tr_tmp.trDelta);
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
// and for crouchersopr0nners
// acceleration
if(history[player][0].t > 0 && history[player][1].t > 0 && history[player][2].t > 0) {
if((VectorDistance(history[player][2].trPos,history[player][1].trPos)/(history[player][1].t-history[player][2].t)) < (VectorDistance(history[player][1].trPos,history[player][0].trPos)/(history[player][0].t-history[player][1].t))) {
speedscale = 1.2;
tr_tmp.trType = TR_ACCELERATE;
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
eth_BG_EvaluateTrajectoryDelta(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
} else {
speedscale = 1.5;
tr_tmp.trType = TR_DECCELERATE;
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
eth_BG_EvaluateTrajectoryDelta(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
}
}
if( (eFlags & EF_PRONE) || (eFlags & EF_PRONE_MOVING) || (eFlags & EF_CROUCHING)) {
if((eFlags & EF_PRONE) || (eFlags & EF_PRONE_MOVING))
speedscale = 1.5;
else if (eFlags & EF_CROUCHING)
speedscale = 1.5;
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
tr_tmp.trType = TR_LINEAR;
eth_BG_EvaluateTrajectoryDelta(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
VectorCopy(history[player][0].prPos,tr_tmp.trDelta);
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
}
VectorCopy(history[player][0].prPos,tr_tmp.trDelta);
tr_tmp.trType = TR_SINE;
tr_tmp.trDuration = delta_time * speedscale;
VectorScale(history[player][0].prPos,speedscale,history[player][0].prPos);
eth.BG_EvaluateTrajectory(&tr_tmp,eth.cg_time + future + (int)(seth.value[VAR_PRED_C]),history[player][0].prPos,qfalse,-1);
VectorScale(tr_tmp.trDelta,speedscale,tr_tmp.trDelta);
if(VectorDistance(history[player][0].prPos,history[player][0].trPos) < 100) {
VectorSubtract(history[player][0].prPos,history[player][0].trPos,history[player][0].prPos);
retval = 1;
} else {
VectorCopy(history[player][0].trDelta,history[player][0].prPos);
retval = 0;
}
//grab every snapshot only
if(history[player][0].t != history[player][0].predictTime && future != 0) {
vec3_t distance;
VectorAdd(history[player][1].trPos,history[player][1].prPos,distance);
eth.predMissed = VectorDistance(distance,history[player][0].trPos);
history[player][0].predictTime=history[player][0].t;
}
//restore original trPos
if(future != 0)
VectorCopy(o_tmp,history[player][0].trPos);
return retval;
}
void eth_interpolate(int player) {
int i;
float f = (float)( eth.cg_time - history[player][1].t ) / ( history[player][0].t - history[player][1].t );
for (i=0;i<3;i++)
history[player][0].trPos[i] = history[player][1].trPos[i] + f * (history[player][0].trPos[i] - history[player][1].trPos[i] );
}
/* kobj: i think this code is bugged...
refentity entity num is not always clientnum (check sdk)
sometimes with eth i had that it would not aim for head or find them...
using this clientnum solved it. not doing anythgn with it but if this happens
you know why and you can change it yourself ;]
*/
void eth_CG_R_AddRefEntityToScene(refEntity_t *refEnt) {
ethEntity_t* entity = ð.entities[refEnt->entityNum];
int entityNum = refEnt->entityNum;
//kobj:
// int clientnum = eth.cg_entities[entityNum].currentState->clientNum;
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);
// kobj: for trac0r
memcpy(&entity->refHead, refEnt, sizeof(refEntity_t));
// Add some vector Z for better display of esp
vec3_t tmpVector;
VectorCopy(entity->head, tmpVector);
tmpVector[ROLL] += 30.0f;
entity->isInScreen = worldToScreen(tmpVector, &entity->screenX, &entity->screenY);
// Backup head axis for mortar trace
memcpy(entity->headAxis, refEnt->axis, sizeof(vec3_t) * 3);
if( seth.value[VAR_AIMFOV] > 0 ){
// Get hitboxes from models
orig_syscall( CG_R_MODELBOUNDS, refEnt->hModel, entity->rmin, entity->rmax );
// Apply vecz
// if((history[entityNum][0].t < eth.cg_time) && (history[entityNum][0].t!=0)) {
//kobj vecz is not necessary with hitbox aiming
// tes: i have other idea, leave it as it is :]
// set 0 do all vecz to get out of hitbox add
if( !seth.value[VAR_HITBOX] )
doVecZ(entityNum);
// tes: maybe there is other way to stop trippin out...
// do simulation 10 miliseconds forward (maybe more)
int sim;
vec3_t tmpPos,nullv;
VectorSet(nullv,0,0,0);
// backup original prPos once per snapshot
VectorCopy(history[entityNum][0].trPos,tmpPos);
for(sim = 1; sim < 3 ; sim++) {
//simulate cmd forward
doPredCalc(tmpPos,entityNum,sim+(eth.cg_snap->ping/CMD_BACKUP -2));
VectorAdd(tmpPos,history[entityNum][0].prPos,tmpPos);
}
VectorAdd(history[entityNum][0].trPos,history[entityNum][0].prPos,tmpPos);
// if we predict too much then fuck it
if(VectorDistance(history[entityNum][0].trPos,tmpPos) <30) {
VectorSet(history[entityNum][0].prPos,0,0,0);
doPredCalc(nullv,entityNum,0);
doPrediction(entityNum);
}
VectorAdd(history[entityNum][0].trPos,history[entityNum][0].prPos,tmpPos);
// printf("Got: %f %f %f [st: %d] | Predicted: %f %f %f [ct: %d]",history[entityNum][0].trPos[0],history[entityNum][0].trPos[1],history[entityNum][0].trPos[2],eth.cg_snap->serverTime,tmpPos[0],tmpPos[1],tmpPos[2],eth.cg_time);
// printf(" [%d %d %d]\n",(int)seth.value[VAR_PRED_C],(int)seth.value[VAR_VECZ],(int)seth.value[VAR_SNAPDELAY]);
// }
// #ifdef ETH_DEBUG
// if (!seth.value[VAR_PREDICT_STATS])
// #endif
}
// 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
vec3_t tmp_v;
VectorAdd(entity->head,history[entityNum][0].prPos,tmp_v);
/* kobj ok this needs some thinking. We want to shoot ppl
if headhitbox is visible, but also shoot if we predict
that it will be visible, ayt?? ok seems no prob so long this is called
after pred code is done.
note: do body trace later, since body trace
is not refent related but lerped_origin... body hitboxes are centered on entity pos, not tag */
//tes: kobject u'r wicked sick :)))
// if(lastTPT != eth.cg_time){
if( seth.value[VAR_HITBOX] ){
if (trace_head(&entity->refHead, entity->head_visible_pt, refEnt->entityNum)){
entity->isVisible = qtrue;
entity->isHeadVisible = qtrue;
}
} else {
if (isVisible(entity->head)) {
entity->isVisible = qtrue;
entity->isHeadVisible = qtrue;
}
}
// Pig head for enemy
if (seth.value[VAR_VISUALS] && seth.value[VAR_PIGHEAD] && IS_PLAYER_ENEMY(entityNum)) {
refEnt->hModel = eth.pigHeadModel;
refEnt->customSkin = eth.pigHeadSkin;
// Chams
} else {
if (seth.value[VAR_VISUALS] && 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
// kobj only do this if not doing hitbox magic to save cpu cycles (i check for body visibily elsewhere)
if (!seth.value[VAR_HITBOX]){
vec3_t target;
if (getVisibleModelBodyTag(entityNum, &target)) {
VectorCopy(target, entity->bodyPart);
entity->isVisible = qtrue;
}
}
// Chams
if (seth.value[VAR_VISUALS] && 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_VISUALS] && 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) {
// Special care if AMMO or HEALTH
} else if( (refEnt->hModel == eth.hMedicPack) || (refEnt->hModel == eth.hAmmoPack) ) {
if( !seth.value[VAR_ESPITEMS] )
return;
if( seth.value[VAR_CHAMS] )
addChams(refEnt, entity->isVisible);
// Not player or missile
} else
return;
// Wallhack
if (seth.value[VAR_VISUALS] && 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) {
static int lastAim;
// Don't draw stuff in intermission
if (eth.cgs_gamestate == GS_INTERMISSION)
return;
setCurrentMuzzle();
switch( (int)seth.value[VAR_KSPAM] ){
case RS1:
strncpy(ksFormat, "^2[v] ^7was owned! (active spree: ^1[c]^7)[1]",sizeof(ksFormat));
break;
case RS2:
strncpy(ksFormat, "^2[v] ^7 was leaked! (Total Leaks: ^1[t]^7)[5]",sizeof(ksFormat));
break;
case RS3:
strncpy(ksFormat, "^2[v][X] ^7(kills: ^1[t]^7)",sizeof(ksFormat));
break;
case CEF:
strncpy(ksFormat, "^2[n] [C] [P]",sizeof(ksFormat));
break;
case RS4:
strncpy(ksFormat, "^2[v] ^7was owned. (Total Kills: ^1[t]^7)[2]",sizeof(ksFormat));
break;
case PRO:
strncpy(ksFormat, "^3[n] ^7was killed. Have fun counting [t] bodies.",sizeof(ksFormat));
break;
case ETB:
strncpy(ksFormat, "^4[n] ^7was fragged![3][e]",sizeof(ksFormat));
break;
case NEX:
strncpy(ksFormat, "^0[^3NEXUS^0] ^nowned ^1>^7[n]^1< ^0| ^nSpree: ^1[c] ^0| ^nTotal: ^1[t] [N]",sizeof(ksFormat));
break;
case ROCK:
strncpy(ksFormat, "^1[n][6] ^7(kills: ^1[t]^7) [R]",sizeof(ksFormat));
break;
case ETH:
strncpy(ksFormat, "^nKillingspree^0: ^2[c] ^0| ^2[n] ^0| ^nWas Killed^2!![R]",sizeof(ksFormat));
break;
case AEK:
strncpy(ksFormat, "^2[v] ^7was victim ^x[c] ^7on this spree",sizeof(ksFormat));
break;
case AEK1:
strncpy(ksFormat, "^2[v] ^7is victim ^x[t]",sizeof(ksFormat));
break;
case EVO:
strncpy(ksFormat, "^9Haha^1! ^1[v] ^9Got Owned^1!",sizeof(ksFormat));
break;
default:
break;
}
#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 (dont steal mouse if wp = ammo/health/etc)
if ( seth.value[VAR_AUTOSHOOT] != AUTOSHOOT_OFF ){
if( isAimbotWeapon(eth.cg_entities[eth.cg_clientNum].currentState->weapon) )
setAction(ACTION_BINDMOUSE1, qfalse);
else
setAction(ACTION_BINDMOUSE1, qtrue);
} 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;
}
/* // kobj: 1337 boxes
if ( seth.value[VAR_HITBOX_DBG] && (eth.cg_time-eth.lastRailtrailTime > RAILTRAIL_INTERVAL) ){
int i=0;
ethEntity_t* ent;
for( ; i<MAX_CLIENTS; i++ ){
ent = ð.entities[i];
if (!IS_PLAYER_VALID(i))
continue;
// for debugging or just nice effects
if( seth.value[VAR_HITBOX_DBG] == 1 && IS_PLAYER_ENEMY(i) ){
debug_head_box( i );
eth.lastRailtrailTime = eth.cg_time;
}
if( seth.value[VAR_HITBOX_DBG] == 2 ){
debug_head_box( i );
eth.lastRailtrailTime = eth.cg_time;
}
}
}*/
// kobj moved body trace here... dont know where else would be good place.
// if(isCommandTime() == 1){
//tes: buggy // kobj check body visibility
if (seth.value[VAR_HITBOX]){
int i=0;
ethEntity_t* ent;
for( ; i<MAX_CLIENTS; i++ ){
ent = ð.entities[i];
// dont bother if head is already visible
if (!IS_PLAYER_VALID(i) || ent->isHeadVisible)
continue;
if (trace_body(i, ent->body_visible_pt))
ent->isVisible = qtrue;
}
}
// if(isCommandTime()==1)
if (lastAim < eth.cg_time) {
doAimbot();
lastAim = eth.cg_time;
}
// }
}
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;
// User setting to not draw anything
if( seth.value[VAR_VISUALS] ){
// Set esp colors from vars
setColors();
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 && (eth.cgs_gamestate != GS_INTERMISSION) ) {
// Custom HUDs
if (seth.value[VAR_CHUD] == HUD_1)
drawCustomHud();
else if (seth.value[VAR_CHUD] == HUD_2)
drawETHhud();
// i like spree
if ((eth.cg_time - eth.startFadeTime) < 2000)
drawSpreeText();
// 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();
if( seth.value[VAR_BANNER] )
drawBanner();
// 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();
}
}
}
qboolean eth_CG_R_RenderScene(refdef_t *refdef) {
char fov[8];
float x;
// tce zoom hack
if (seth.value[VAR_WEAPZOOM] && eth.mod->type == MOD_TCE) {
static float lastfx = 0.0f;
static float lastfy = 0.0f;
static int twidth = 0;
static int theight = 0;
// Init max fov
if (lastfx == 0.0f)
lastfx = refdef->fov_x;
if (lastfy == 0.0f)
lastfy = refdef->fov_y;
if (refdef->x < 2) {
//"fixed" fov for aiming mode
if (refdef->fov_x < lastfx)
refdef->fov_x = lastfx;
if (refdef->fov_y < lastfy)
refdef->fov_y = lastfy;
// init max w and h
if (!twidth || twidth < refdef->width)
twidth = refdef->width;
if (!theight || theight < refdef->height)
theight = refdef->height;
} else {
// increase zoom win a little
if (refdef->x > 21) {
refdef->x -= 20;
refdef->width += 40;
}
if (refdef->y > 51) {
refdef->y -= 20;
refdef->height += 40;
}
// Simple fov correction for scope
if (twidth && theight) {
refdef->fov_x = (lastfx * refdef->width) / twidth;
refdef->fov_y = (lastfy * refdef->height) / theight;
// Decide which way is better but it's not good enough
//float tcx = refdef->width / tan(refdef->fov_x / 360 * M_PI);
//refdef->fov_y = atan2(refdef->height, tcx);
//refdef->fov_y *= 360 / M_PI;
}
}
}
// 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 spy cam
switch (eth.cg_entities[eth.cg_snap->ps.clientNum].currentState->weapon) {
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;
}
// Return qfalse if this pic don't have to be draw
qboolean eth_CG_R_DrawStretchPic(float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader) {
adjustTo640(&x, &y, &w, &h);
// Remove sniper/binocular picture
if (eth.mod->type == MOD_TCE) {
if (hShader == eth.tcescope1 || hShader == eth.tcescope2 || hShader == eth.cgs_media_reticleShaderSimple)
return qfalse;
if ((int)w > 20 && (int)h > 40 && hShader == eth.cgs_media_whiteShader )
return qfalse;
if ((((int)w < 7 && (int)h > 40) || ((int)h < 7 && (int)w > 40)) && hShader == eth.cgs_media_whiteShader )
return qfalse;
if (((int)w < 7 && (int)h < 7) && hShader == eth.cgs_media_whiteShader )
return qfalse;
} else {
if (hShader == eth.cgs_media_reticleShaderSimple || hShader == eth.cgs_media_binocShaderSimple)
return qfalse;
}
// Remove sniper/binocular black area
if (((int)y == 0) && ((int)w == 80) && (hShader == eth.cgs_media_whiteShader))
return qfalse;
// Remove zoom black fade in/out and flashbang in tce
if (((int)x == -10) && ((int)y == -10) && ((int)w == 650) && ((int)h == 490) && (hShader == eth.cgs_media_whiteShader))
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_PREPARE], 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 and revive spree
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_FALL_SHORT:
case EV_FALL_DMG_10:
case EV_FALL_DMG_15:
case EV_FALL_DMG_25:
case EV_FALL_DMG_50:
case EV_CONCUSSIVE:
if (es->number == eth.cg_clientNum)
return;
//tes: ^^ this need to be corrected in local sounds
case EV_FIRE_WEAPON:
if( seth.value[VAR_RECOIL] == 2)
if (es->number == eth.cg_clientNum) {
syscall_CG_S_StartLocalSound(eth.cgs_media_sndLimboSelect, CHAN_LOCAL_SOUND);
return;
}
break;
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) {
if( attacker > MAX_CLIENTS )
strncpy( eth.KillerName, "world" ,sizeof(eth.KillerName) );
else
strncpy( eth.KillerName, eth.clientInfo[attacker].name,sizeof(eth.KillerName) );
if (seth.value[VAR_KILLSPAM] && target != attacker)
deathSpam();
if (seth.value[VAR_KILLSPAM] && target == attacker)
selfkillSpam();
eth.killCountNoDeath = 0;
eth.killSpreeCount = 0;
eth.reviveSpree = 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_WeaponFireRecoil(int weapon){
if( seth.value[VAR_RECOIL]==1 )
eth.CG_WeaponFireRecoil( weapon );
return;
}
void eth_CG_DamageFeedback(int yawByte, int pitchByte, int damage){
if( seth.value[VAR_RECOIL]==1 )
eth.CG_DamageFeedback( yawByte, pitchByte, damage );
return;
}
// landmine hack
void eth_CG_Missile( centity_t *cent ) {
if( !cent )
return;
if( cent->currentState.weapon == WP_LANDMINE && seth.value[VAR_ESPMINES] ){
team_t *cgsTeam;
if( eth.mod->cgs ){
int offset = eth.mod->cgs + eth.mod->clientInfoOffset + 0x88; // 2*MAX_QPATH + 8;
cgsTeam = (team_t *) ((void *)(eth.cgameLibAddress + offset+eth.mod->clientInfoSize*eth.cg_clientNum));
} else
cgsTeam = ð.cgs->clientinfo[eth.cg_clientNum].team;
team_t oldTeam = *cgsTeam;
team_t mineTeam = (!cent->currentState.otherEntityNum2 ? TEAM_ALLIES : TEAM_AXIS);
if( *cgsTeam == TEAM_SPECTATOR ){
*cgsTeam = mineTeam;
eth.CG_Missile( cent );
*cgsTeam = TEAM_SPECTATOR;
return;
}
*cgsTeam = mineTeam;
eth.CG_Missile( cent );
*cgsTeam = oldTeam;
return;
}
eth.CG_Missile( cent );
}
void eth_CG_DrawActiveFrame(void) { //under frame
static int lastAim;
custom_headhitbox.stand_offset[0] = seth.value[VAR_CUSTOM_HITBOX_STAND_X];
custom_headhitbox.stand_offset[1] = seth.value[VAR_CUSTOM_HITBOX_STAND_Y];
custom_headhitbox.stand_offset[2] = seth.value[VAR_CUSTOM_HITBOX_STAND_Z];
custom_headhitbox.prone_offset[0] = seth.value[VAR_CUSTOM_HITBOX_PRONE_X];
custom_headhitbox.prone_offset[1] = seth.value[VAR_CUSTOM_HITBOX_PRONE_Y];
custom_headhitbox.prone_offset[2] = seth.value[VAR_CUSTOM_HITBOX_PRONE_Z];
custom_headhitbox.crouch_offset[0] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_X];
custom_headhitbox.crouch_offset[1] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_Y];
custom_headhitbox.crouch_offset[2] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_Z];
custom_headhitbox.stand_offset_moving[0] = seth.value[VAR_CUSTOM_HITBOX_STAND_MOVING_X];
custom_headhitbox.stand_offset_moving[1] = seth.value[VAR_CUSTOM_HITBOX_STAND_MOVING_Y];
custom_headhitbox.stand_offset_moving[2] = seth.value[VAR_CUSTOM_HITBOX_STAND_MOVING_Z];
custom_headhitbox.crouch_offset_moving[0] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_MOVING_X];
custom_headhitbox.crouch_offset_moving[1] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_MOVING_Y];
custom_headhitbox.crouch_offset_moving[2] = seth.value[VAR_CUSTOM_HITBOX_CROUCH_MOVING_Z];
}
/*
==============================
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);
}
//