// GPL License - see http://opensource.org/licenses/gpl-license.php // Copyright 2006 *nixCoders team - don't forget to credit us /* ============================== All aimbot related funtions ============================== */ #include "eth.h" #include "offsets.h" void aimAt(vec3_t target) { #ifdef ETH_DEBUG if (seth.value[VAR_AIM_POINT] == AIM_POINT_2D) { #define POINT_SIZE 4 int x, y; if (worldToScreen(target, &x, &y)) drawFillRect(x - (POINT_SIZE / 2), y - (POINT_SIZE / 2), POINT_SIZE, POINT_SIZE, colorYellow); } else if (seth.value[VAR_AIM_POINT] == AIM_POINT_3D) { crossRailTrail(target); } #endif vec3_t org, ang; // Self Prediction if (seth.value[VAR_SELFPREDICT]) { vec3_t pVieworg; if (seth.value[VAR_SELFPREDICT]) { VectorMA(eth.cg_refdef.vieworg, (float)(eth.cg_frametime) / 1000.0f, eth.cg_entities[eth.cg_clientNum].currentState->pos.trDelta, pVieworg); } else { ethLog("error: invalid aim prediction type: %i", seth.value[VAR_SELFPREDICT]); VectorCopy(eth.cg_refdef.vieworg, pVieworg); } VectorSubtract(target, pVieworg, org); } else { VectorSubtract(target, eth.cg_refdef.vieworg, org); } vectoangles(org, ang); ang[PITCH] -= eth.cg_refdefViewAngles[PITCH]; ang[YAW] -= eth.cg_refdefViewAngles[YAW]; // Simple human aim for now - will try to make it cg_time based, not framebased like now if (seth.value[VAR_HUMAN]) { while (ang[PITCH] < -360.0f) ang[PITCH] += 360.0f; while (ang[PITCH] > 360.0f) ang[PITCH] -= 360.0f; while (ang[YAW] < -360.0f) ang[YAW] += 360.0f; while (ang[YAW] > 360.0f) ang[YAW] -= 360.0f; if (ang[PITCH] > 180.0f) ang[PITCH] -= 360.0f; if (ang[PITCH] < -180.0f) ang[PITCH] += 360.0f; if (ang[YAW] > 180.0f) ang[YAW] -= 360.0f; if (ang[YAW] < -180.0f) ang[YAW] += 360.0f; ang[PITCH] *= seth.value[VAR_HUMANVALUE]*0.9; ang[YAW] *= seth.value[VAR_HUMANVALUE]; if(ang[PITCH] <0) ang[PITCH]*=0.05; } *(float *)sethET->cl_mouseDx += ang[PITCH]; *(float *)sethET->cl_mouseDy += ang[YAW]; // *(float *)CL_MOUSEDX_ADDR += AngleDelta(ang[PITCH], seth.refdefViewAngles[PITCH]); // *(float *)CL_MOUSEDY_ADDR += AngleDelta(ang[YAW], seth.refdefViewAngles[YAW]); } void riffleAimAt(vec3_t target) { vec3_t org, ang; VectorSubtract(target, eth.cg_refdef.vieworg, org); vectoangles(org, ang); // Calculate y distance vec3_t me, enemy; VectorCopy(eth.cg_refdef.vieworg, me); VectorCopy(target, enemy); me[ROLL] = 0; enemy[ROLL] = 0; float y = target[ROLL] - eth.cg_refdef.vieworg[ROLL]; float v = 2000; // Riffle speed float g = DEFAULT_GRAVITY; float x = VectorDistance(me, enemy); float angle = atan((pow(v, 2) - (sqrt(pow(v, 4) + (g * ((g * pow(x, 2)) + (2.0f * y * pow(v, 2))))))) / (g * x)); angle = RAD2DEG(angle); ang[PITCH] = angle; ang[PITCH] -= eth.cg_refdefViewAngles[PITCH]; ang[YAW] -= eth.cg_refdefViewAngles[YAW]; *(float *)sethET->cl_mouseDx += ang[PITCH]; *(float *)sethET->cl_mouseDy += ang[YAW]; } // This tag are in priority order. The first tags are near the center of the // models, the last tag are at edge of the models static char *modelBodyTags[] = { "tag_chest", "tag_torso", "tag_bright", "tag_lbelt", "tag_bleft", "tag_ubelt", "tag_back", "tag_armleft", "tag_weapon", "tag_armright", "tag_weapon2", "tag_legright", "tag_legleft", "tag_footleft", "tag_footright" }; qboolean getVisibleModelBodyTag(const int player, vec3_t *origin) { int count = 0; for (; count < (sizeof(modelBodyTags) / sizeof(char *)); count++) { char *tagText = modelBodyTags[count]; orientation_t tagOrientation; if (!eth_CG_GetTag(player, tagText, &tagOrientation)) ethLog("error: can't find tag %i[%s] for player: %i", count, tagText, player); if (isVisible(tagOrientation.origin)) { VectorCopy(tagOrientation.origin, *origin); #ifdef ETH_DEBUG ethDebug("found visible tag: %s for player: %i", tagText, player); #endif return qtrue; } } return qfalse; } void doAutoShoot(qboolean shoot) { // We don't want autoshoot if (!seth.value[VAR_AUTOSHOOT]) return; // Don't shoot if we're specing/following a player if (eth.cg_clientNum != eth.cg_snap->ps.clientNum) return; qboolean trigger; // *----------------------------------------------------------------------* static int anylastShootTime = 0; if ((eth.cg_time - anylastShootTime) >= (seth.value[VAR_SNIPERDELAY])) { anylastShootTime = eth.cg_time; setAction(ACTION_ATTACK, 0); // u can remove it for testing so leave return only; return; } // *----------------------------------------------------------------------* if (seth.value[VAR_AUTOSHOOT_TYPE] == AUTOSHOOT_TYPE_TRIGGER) { // Set a far away end point vec3_t aheadPos; VectorMA(eth.cg_refdef.vieworg, 8192, eth.cg_refdef.viewaxis[0], aheadPos); // Get trace for this point trace_t trace; eth.CG_Trace(&trace, eth.cg_refdef.vieworg, NULL, NULL, aheadPos, eth.cg_snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_ITEM); trigger = IS_PLAYER_ENEMY(trace.entityNum); // Don't use trigger } else { trigger = qtrue; } // For tce if (eth.mod->type == MOD_TCE) { if (shoot && trigger && (syscall_CG_Key_IsDown(K_MOUSE1) || (seth.value[VAR_AUTOSHOOT] == AUTOSHOOT_ON))) { static qboolean lastFrameAttack = qfalse; if (!lastFrameAttack) { setAction(ACTION_ATTACK, 1); lastFrameAttack = qtrue; } else { setAction(ACTION_ATTACK, 0); lastFrameAttack = qfalse; } } else { setAction(ACTION_ATTACK, 0); } // For all others mod } else { if (shoot && trigger && (syscall_CG_Key_IsDown(K_MOUSE1) || (seth.value[VAR_AUTOSHOOT] == AUTOSHOOT_ON))) { // Check for sniper weapon delay if (((eth.cg_entities[eth.cg_clientNum].currentState->weapon == WP_K43_SCOPE) || (eth.cg_entities[eth.cg_clientNum].currentState->weapon == WP_GARAND_SCOPE)) && !BG_PlayerMounted(eth.cg_snap->ps.eFlags)) { static int lastShootTime = 0; if ((eth.cg_time - lastShootTime) >= (seth.value[VAR_SNIPERDELAY])) { setAction(ACTION_ATTACK, 1); lastShootTime = eth.cg_time; } else { setAction(ACTION_ATTACK, 0); } // Check for weapon overheating #define OVERHEATING_LIMIT 200 } else if (seth.value[VAR_OVERHEAT] && (eth.cg_snap->ps.curWeapHeat > OVERHEATING_LIMIT)) { setAction(ACTION_ATTACK, 0); } else { setAction(ACTION_ATTACK, 1); #ifdef ETH_DEBUG ethDebug("autoshoot: shoot on"); #endif } } else { setAction(ACTION_ATTACK, 0); #ifdef ETH_DEBUG ethDebug("autoshoot: shoot off"); #endif } } } void doSatchelAutoShoot() { int satchelEntityNum = findSatchel(); // If don't find satchel if (satchelEntityNum == -1) { #ifdef ETH_DEBUG ethDebug("autoshoot: don't find satchel for %i", eth.cg_snap->ps.clientNum); #endif setAction(ACTION_ATTACK, 0); return; } // Find an enemy near the satchel #define SATCHEL_SHOOT_DISTANCE 100 int entityNum = 0; for (; entityNum < MAX_CLIENTS; entityNum++) { ethEntity_t *entity = ð.entities[entityNum]; if (entity->isValid && IS_PLAYER_ENEMY(entityNum) && (VectorDistance(entity->origin, eth.entities[satchelEntityNum].origin) < SATCHEL_SHOOT_DISTANCE)) { setAction(ACTION_ATTACK, 1); return; } } // TODO: find a breakable object near the satchel setAction(ACTION_ATTACK, 0); } int findTarget(int targetFlag) { int nearest = -1; int maxEntities = MAX_GENTITIES; // Get max entities if (targetFlag & TARGET_PLAYER) maxEntities = MAX_CLIENTS; int entityNum = 0; if( (seth.value[VAR_TARGET_PRIO] == TARGET_ATTACKER ) ){ int ent = eth.cg_snap->ps.persistant[PERS_ATTACKER]; if( ent && ent <= MAX_CLIENTS ){ // Jaymod 2.1.x aimbot workaround if( eth.mod->crc32 == 0x5f24fa23 || eth.mod->crc32 == 0x8352a951 ) eth.cg_entities[ent].currentState->eType = ET_PLAYER; if( ((targetFlag & TARGET_ENEMY) && (targetFlag & TARGET_PLAYER) && IS_PLAYER_ENEMY(entityNum)) && eth.entities[ent].isVisible && !IS_PLAYER_DEAD(ent) ) return ent; } } for (; entityNum < maxEntities; entityNum++) { ethEntity_t* entity = ð.entities[entityNum]; if (!*eth.cg_entities[entityNum].currentValid || (entityNum == eth.cg_snap->ps.clientNum)) continue; // Jaymod 2.1.x aimbot workaround if( entityNum < MAX_CLIENTS && (eth.mod->crc32 == 0x5f24fa23 || eth.mod->crc32 == 0x8352a951) ) eth.cg_entities[entityNum].currentState->eType = ET_PLAYER; // Player if ((targetFlag & TARGET_PLAYER) && !IS_PLAYER_VALID(entityNum)) continue; if ((targetFlag & TARGET_PLAYER_VULN) && !IS_PLAYER_VULNERABLE(entityNum)) continue; if ((targetFlag & TARGET_PLAYER_ALIVE) && IS_PLAYER_DEAD(entityNum)) continue; if ((targetFlag & TARGET_PLAYER_DEAD) && !IS_PLAYER_DEAD(entityNum)) continue; // Target if ((targetFlag & TARGET_PLAYER_HEAD) && !entity->isHeadVisible) continue; if ((targetFlag & TARGET_PLAYER_BODY) && VectorCompare(entity->bodyPart, vec3_origin)) continue; // Targeting specific player has priority over other settings if ( (targetFlag & TARGET_VISIBLE) && entity->isVisible && (seth.value[VAR_TARGET_PRIO]==TARGET_PERSON) && eth.clAttack[entityNum] ) return entityNum; // Common if ((targetFlag & TARGET_ENEMY) && (targetFlag & TARGET_PLAYER) && !IS_PLAYER_ENEMY(entityNum)) continue; if ((targetFlag & TARGET_ENEMY) && (targetFlag & TARGET_MISSILE) && !IS_MISSILE_ENEMY(entityNum)) continue; if ((targetFlag & TARGET_FRIEND) && (targetFlag & TARGET_PLAYER) && IS_PLAYER_ENEMY(entityNum)) continue; if ((targetFlag & TARGET_FRIEND) && (targetFlag & TARGET_MISSILE) && IS_MISSILE_ENEMY(entityNum)) continue; if ((targetFlag & TARGET_VISIBLE) && !entity->isVisible) continue; if ((targetFlag & TARGET_NOTVISIBLE) && entity->isVisible) continue; // Missile if ((targetFlag & TARGET_MISSILE) && !IS_MISSILE(entityNum)) continue; if ((targetFlag & TARGET_MISSILE_ARMED) && !IS_MISSILE_ARMED(entityNum)) continue; if ((targetFlag & TARGET_MISSILE_NOTARMED) && IS_MISSILE_ARMED(entityNum)) continue; if ((targetFlag & TARGET_MISSILE_DYNAMITE) && !IS_DYNAMITE(entityNum)) continue; if( (seth.value[VAR_TARGET_PRIO] == TARGET_NOOBTUBE) && IS_PANZER(entityNum) ) return entityNum; if( (seth.value[VAR_TARGET_PRIO] == TARGET_MG42) && IS_MG42(entityNum) ) return entityNum; if( (seth.value[VAR_TARGET_PRIO] == TARGET_HEAVY) && (IS_HEAVYWP(entityNum) )) return entityNum; if (seth.value[VAR_AIMFOV] != 360.00f) { vec3_t aimPoint, ang, org; if (eth.entities[entityNum].isHeadVisible) VectorCopy(eth.entities[entityNum].head, aimPoint); else if (seth.value[VAR_AIM_PRIO] != AIM_PRIO_HEAD_ONLY) VectorCopy(eth.entities[entityNum].bodyPart, aimPoint); else { ethLog("findTarget: can't find a point to aim"); return -1; } VectorSubtract(aimPoint, eth.cg_refdef.vieworg, org); vectoangles(org, ang); ang[PITCH] -= eth.cg_refdefViewAngles[PITCH]; ang[YAW] -= eth.cg_refdefViewAngles[YAW]; if (ang[PITCH] < 0.0) ang[PITCH] *= -1.0; if (ang[YAW] < 0.0) ang[YAW] *= -1.0; if (ang[PITCH] > 360.0f) ang[PITCH] -= 360.0f; if (ang[YAW] > 360.0f) ang[YAW] -= 360.0f; float aimFov[2]; aimFov[0] = (ang[PITCH] - 360.0) * -1.0; aimFov[1] = (ang[YAW] - 360.0) * -1.0; if (ang[PITCH] > aimFov[0]) ang[PITCH] = aimFov[0]; if (ang[YAW] > aimFov[1]) ang[YAW] = aimFov[1]; if ((ang[PITCH] > seth.value[VAR_AIMFOV]) || (ang[YAW] > seth.value[VAR_AIMFOV])) continue; } if ((entity->distance != 0) && (nearest == -1 || (entity->distance < eth.entities[nearest].distance))) { nearest = entityNum; } } #ifdef ETH_DEBUG if (nearest != -1) ethDebug("findTarget: target found for flags 0x%x", targetFlag); else ethDebug("findTarget: target not found for flags 0x%x", targetFlag); #endif return nearest; } void blockMouse(qboolean state) { if (!seth.value[VAR_BLOCK_MOUSE]) return; #define SENSITIVITY_STR "sensitivity" static float sensitivity = 0; // For backup user sensitivity static qboolean mouseBlocked = qfalse; // Current state char buffer[32]; // Set sensitivity if (state && !mouseBlocked) { syscall_CG_Cvar_VariableStringBuffer(SENSITIVITY_STR, buffer, sizeof(buffer)); sensitivity = atof(buffer); syscall_CG_SendConsoleCommand(SENSITIVITY_STR " 0\n"); mouseBlocked = qtrue; #ifdef ETH_DEBUG ethDebug("blockMouse: mouse off"); #endif } else if (!state && mouseBlocked) { snprintf(buffer, sizeof(buffer), SENSITIVITY_STR " %f\n", sensitivity); syscall_CG_SendConsoleCommand(buffer); mouseBlocked = qfalse; #ifdef ETH_DEBUG ethDebug("blockMouse: mouse on"); #endif } } void doAimbot() { qboolean autoShootWeapon = qfalse; int targetFlag[2] = { -1, -1 }; // If a targetFlag failed try the next one // For tce if (eth.mod->type == MOD_TCE) { int clips = eth.cg_snap->ps.ammoclip[eth.cg_snap->ps.weapon]; int ammo = eth.cg_snap->ps.ammo[eth.cg_snap->ps.weapon]; static qboolean lastframeReload = qfalse; if(clips == 0 && ammo > 0) { if(eth.cg_snap->ps.weapon != WP_KNIFE) if(!lastframeReload) { setAction(ACTION_RELOAD, 1); lastframeReload = qtrue; return; } } if(lastframeReload) { setAction(ACTION_RELOAD, 0); lastframeReload = qfalse; } autoShootWeapon = qtrue; targetFlag[0] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_ALIVE; // Aim priority if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD_BODY) { targetFlag[0] |= TARGET_PLAYER_HEAD_BODY; } else if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD_ONLY) { targetFlag[0] |= TARGET_PLAYER_HEAD; } else if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD) { targetFlag[1] = targetFlag[0] | TARGET_PLAYER_BODY; targetFlag[0] |= TARGET_PLAYER_HEAD; } // For all others mod } else { // if player is mounted (tank mg, mobile mg42, static mg42) aim for body if (BG_PlayerMounted(eth.cg_snap->ps.eFlags) || (eth.cg_snap->ps.weapon == WP_MOBILE_MG42) || (eth.cg_snap->ps.weapon == WP_MOBILE_MG42_SET)) { autoShootWeapon = qtrue; targetFlag[0] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_BODY; if (!seth.value[VAR_AIM_DEAD]) targetFlag[0] |= TARGET_PLAYER_ALIVE; targetFlag[1] = targetFlag[0] | TARGET_PLAYER_HEAD; } else { // different targets for differents weapons switch (eth.cg_snap->ps.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_GARAND: case WP_K43: case WP_FG42: case WP_STEN: case WP_CARBINE: case WP_KAR98: autoShootWeapon = qtrue; targetFlag[0] = TARGET_PLAYER_ENEMY; // Aim at dead player if (!seth.value[VAR_AIM_DEAD]) targetFlag[0] |= TARGET_PLAYER_ALIVE; // Aim priority if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD_BODY) { targetFlag[0] |= TARGET_PLAYER_HEAD_BODY; } else if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD_ONLY) { targetFlag[0] |= TARGET_PLAYER_HEAD; } else if (seth.value[VAR_AIM_PRIO] == AIM_PRIO_HEAD) { targetFlag[1] = targetFlag[0] | TARGET_PLAYER_BODY; targetFlag[0] |= TARGET_PLAYER_HEAD; } break; case WP_GPG40: case WP_M7: autoShootWeapon = qtrue; targetFlag[0] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_ALIVE | TARGET_PLAYER_BODY; break; case WP_GARAND_SCOPE: case WP_K43_SCOPE: case WP_FG42SCOPE: autoShootWeapon = qtrue; targetFlag[0] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_ALIVE | TARGET_PLAYER_HEAD; break; case WP_KNIFE: targetFlag[0] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_ALIVE | TARGET_PLAYER_HEAD; targetFlag[1] = TARGET_PLAYER_ENEMY | TARGET_PLAYER_DEAD | TARGET_PLAYER_HEAD; break; case WP_MEDIC_SYRINGE: targetFlag[0] = TARGET_PLAYER | TARGET_FRIEND | TARGET_PLAYER_DEAD | TARGET_PLAYER_BODY; break; case WP_PLIERS: targetFlag[0] = TARGET_MISSILE | TARGET_MISSILE_DYNAMITE | TARGET_ENEMY | TARGET_MISSILE_ARMED; targetFlag[1] = TARGET_MISSILE | TARGET_MISSILE_DYNAMITE | TARGET_FRIEND | TARGET_MISSILE_NOTARMED; default: break; } } } // Check if we want aimbot if ((syscall_CG_Key_IsDown(K_MOUSE1) || seth.value[VAR_AIM_AUTO]) && (targetFlag[0] != -1) && seth.value[VAR_AIM_PRIO] && (eth.cg_snap->ps.clientNum == eth.cg_clientNum) ) { // Find target aim point int count = 0; int target; for (; count < (sizeof(targetFlag) / sizeof(int)); count++) { if (targetFlag[count] != -1) { vec3_t aimPoint; VectorCopy(vec3_origin, aimPoint); target = findTarget(targetFlag[count]); // No target found if (target == -1) continue; // Target found if (targetFlag[count] & TARGET_PLAYER) { if (targetFlag[count] & TARGET_PLAYER_HEAD) { VectorCopy(eth.entities[target].head, aimPoint); #ifdef ETH_DEBUG ethDebug("aimbot: found head player: %s", eth.clientInfo[target].name); #endif } else if (targetFlag[count] & TARGET_PLAYER_BODY) { VectorCopy(eth.entities[target].bodyPart, aimPoint); #ifdef ETH_DEBUG ethDebug("aimbot: found body player: %s", eth.clientInfo[target].name); #endif } else if (targetFlag[count] & TARGET_PLAYER_HEAD_BODY) { // Head or body ? if (eth.entities[target].isHeadVisible) VectorCopy(eth.entities[target].head, aimPoint); else VectorCopy(eth.entities[target].bodyPart, aimPoint); #ifdef ETH_DEBUG ethDebug("aimbot: found head/body player: %s", eth.clientInfo[target].name); #endif } else { ethLog("error: target found but no aimpoint set in target flags"); } } else if (targetFlag[count] & TARGET_MISSILE) { VectorCopy(eth.entities[target].origin, aimPoint); #ifdef ETH_DEBUG ethDebug("aimbot: found missile: %i", target); #endif } else { ethLog("error: target found but it's not a player/missile"); } // If aim point is set, aim and shoot if (!VectorCompare(aimPoint, vec3_origin)) { if (!seth.value[VAR_HUMAN]) doAutoShoot(qtrue); if ((eth.cg_snap->ps.weapon == WP_GPG40) || (eth.cg_snap->ps.weapon == WP_M7)) riffleAimAt(aimPoint); else aimAt(aimPoint); blockMouse(qtrue); return; } } } #ifdef ETH_DEBUG ethDebug("aimbot: no target found"); #endif } blockMouse(qfalse); // For satchel if (seth.value[VAR_SATCHEL_AUTOSHOOT] && (eth.cg_entities[eth.cg_clientNum].currentState->weapon == WP_SATCHEL_DET) && (eth.mod->type != MOD_TCE)) { doSatchelAutoShoot(); // All others weapons } else { doAutoShoot(!autoShootWeapon); } } void doVecZ(int player) { ethEntity_t *entity = ð.entities[player]; // No need if not an enemy if (!IS_PLAYER_ENEMY(player)) return; // For tce if (eth.mod->type == MOD_TCE) { VectorMA(entity->head, seth.value[VAR_VECZ], entity->headAxis[2], entity->head); // For all others mod } else { // Set different vecz for different weapon switch (eth.cg_snap->ps.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_MOBILE_MG42: case WP_GARAND: case WP_K43: case WP_FG42: case WP_STEN: case WP_CARBINE: case WP_KAR98: case WP_GARAND_SCOPE: case WP_K43_SCOPE: case WP_FG42SCOPE: if (seth.value[VAR_AIMVECZ_TYPE] == VECZ_HITBOX) { vec3_t rmin; vec3_t rmax; VectorCopy(entity->rmin,rmin); VectorCopy(entity->rmax,rmax); // -> u can test it SnapVector(entity->head);//simple entity->head[0]=entity->head[0]+(rmin[0]+rmax[0])*0.5f; entity->head[1]=entity->head[1]+(rmin[1]+rmax[1])*0.5f; entity->head[2]=entity->head[2]+(rmin[2]+rmax[2])*0.5f; #ifdef ETH_DEBUG //Debugstuph - use functions from: http://www.nixcoders.org/forum/index.php?showtopic=538 // if (seth.value[VAR_HITBOX] && syscall_CG_Key_IsDown(K_MOUSE1)) { // drawHeadBox(rmin,rmax,entity->head); // } #endif } else if (seth.value[VAR_AIMVECZ_TYPE] == VECZ_MANUAL) { // Simple vecz correction switch (eth.cg_snap->ps.weapon) { case WP_STEN: VectorMA(entity->head, seth.value[VAR_VECZ_STEN], entity->headAxis[2], entity->head); break ; case WP_K43_SCOPE: case WP_GARAND_SCOPE: case WP_FG42SCOPE: VectorMA(entity->head, seth.value[VAR_VECZ_SCOPE], entity->headAxis[2], entity->head); break; default: VectorMA(entity->head, seth.value[VAR_VECZ], entity->headAxis[2], entity->head); break; } // Auto vecz } else if (seth.value[VAR_AIMVECZ_TYPE] == VECZ_AUTO) { #define NEAR_TARGET_VECZ 5.0f // Scoped weapons always aim at the middle of head if (eth.cg_snap->ps.weapon == WP_GARAND_SCOPE || eth.cg_snap->ps.weapon == WP_K43_SCOPE || eth.cg_snap->ps.weapon == WP_FG42SCOPE) { VectorMA(entity->head, 5.0f, entity->headAxis[2], entity->head); return; } // Different 'near distance' for sten int nearTarget; if (eth.cg_snap->ps.weapon == WP_STEN) nearTarget = 700.0f; else nearTarget = 500.0f; if (entity->distance <= nearTarget) VectorMA(entity->head, NEAR_TARGET_VECZ, entity->headAxis[2], entity->head); else if ((entity->distance > nearTarget) && (entity->distance < 2000.0f)) VectorMA(entity->head, (NEAR_TARGET_VECZ * (100.0f - ((entity->distance - nearTarget) / 15.0f))) / 100.0f, entity->headAxis[2], entity->head); } break; default: break; } } } void doPrediction(int player) { // No predicton if (!seth.value[VAR_AIMPREDICT]) return; ethEntity_t *entity = ð.entities[player]; //eth.BG_EvaluateTrajectory(ð.cg_entities[player].currentState->pos, *eth.cg.time + eth.cg_frametime, entity->origin, qfalse, 0); //eth.BG_EvaluateTrajectory(ð.cg_entities[player].currentState->pos, *eth.cg.time + (seth.value[VAR_AIMPREDICT_VALUE] * 100.0f), entity->origin, qfalse, 0); // Frametime prediction based if (seth.value[VAR_AIMPREDICT] == AIMPREDICT_AUTO_1) { VectorMA(entity->origin, (float)(eth.cg_frametime) / 1000.0f, eth.cg_entities[player].currentState->pos.trDelta, entity->origin); //VectorMA(entity->head, (float)(eth.cg_frametime) / 1000.0f, eth.cg_entities[player].currentState->pos.trDelta, entity->head); VectorMA (entity->head, eth.cg_snap->ping / 800, eth.cg_entities[player].currentState->pos.trDelta, entity->head); } else if (seth.value[VAR_AIMPREDICT] == AIMPREDICT_AUTO_2) { vec3_t velocity; VectorScale(eth.cg_entities[player].currentState->pos.trDelta, 1000.0f / ((float)(eth.cg_frametime) - eth.cg_entities[player].currentState->pos.trTime) , velocity); VectorMA(entity->origin, (float)(eth.cg_frametime) / 1000.0f, velocity, entity->origin); VectorMA(entity->head, (float)(eth.cg_frametime) / 1000.0f, velocity, entity->head); } else ethLog("error: invalid aim prediction type: %i", seth.value[VAR_AIMPREDICT]); } #ifdef ETH_DEBUG void doPredictionStats() { static int lastTarget = -1; int target = -1; // Find the nearest moving player int count; int targetDistance = -1; static vec3_t lastPosition[MAX_CLIENTS]; for (count = 0; count < MAX_CLIENTS; count++) { // If valid and moving if (IS_PLAYER_VALID(count) && !VectorCompare(lastPosition[count], eth.entities[count].origin)) { // If nearest if ((targetDistance == -1) || (eth.entities[count].distance < targetDistance)) { target = count; targetDistance = eth.entities[count].distance; } } } // Backup for next frame lastTarget = target; // Store all players positions for next frame for (count = 0; count < MAX_CLIENTS; count++) { if (IS_PLAYER_VALID(count)) VectorCopy(eth.entities[count].origin, lastPosition[count]); } // If no target found or not the same target if ((target == -1) || (lastTarget != target)) return; // Init prediction stats ethEntity_t *entity = ð.entities[target]; static vec3_t lastOrigin; static vec3_t lastPredictOrigin; // Draw stats drawPredictStats(lastOrigin, entity->origin, lastPredictOrigin); printf("---------\n"); printf("origin : %.1f %.1f %.1f\n", lastOrigin[0], lastOrigin[1], lastOrigin[2]); printf("real : %.1f %.1f %.1f\n", entity->origin[0], entity->origin[1], entity->origin[2]); printf("predict: %.1f %.1f %.1f\n", lastPredictOrigin[0], lastPredictOrigin[1], lastPredictOrigin[2]); // Backup var for next frame VectorCopy(entity->origin, lastOrigin); doPrediction(target); // Backup var for next frame VectorCopy(entity->origin, lastPredictOrigin); } #endif // ETH_DEBUG