text: #include "Aimbot.h"
  #include "../Config.h"
  #include "../Interfaces.h"
  #include "../Memory.h"
  #include "../SDK/Entity.h"
  #include "../SDK/UserCmd.h"
  #include "../SDK/Vector.h"
  #include "../SDK/WeaponId.h"
  #include "../SDK/GlobalVars.h"
  #include "../SDK/PhysicsSurfaceProps.h"
  #include "../SDK/WeaponData.h"
  
  Vector Aimbot::calculateRelativeAngle(const Vector& source, const Vector& destination, const Vector& viewAngles) noexcept
  {
      return ((destination - source).toAngle() - viewAngles).normalize();
  }
  
  static bool traceToExit(const Trace& enterTrace, const Vector& start, const Vector& direction, Vector& end, Trace& exitTrace)
  {
      const auto traceToExitFn = memory->traceToExit;
      bool result;
      __asm {
          push exitTrace
          mov eax, direction
          push [eax]Vector.z
          push [eax]Vector.y
          push [eax]Vector.x
          mov eax, start
          push [eax]Vector.z
          push [eax]Vector.y
          push [eax]Vector.x
          mov edx, enterTrace
          mov ecx, end
          call traceToExitFn
          add esp, 28
          mov result, al
      }
      return result;
  }
  
  static float handleBulletPenetration(SurfaceData* enterSurfaceData, const Trace& enterTrace, const Vector& direction, Vector& result, float penetration, float damage) noexcept
  {
      Vector end;
      Trace exitTrace;
  
      if (!traceToExit(enterTrace, enterTrace.endpos, direction, end, exitTrace))
          return -1.0f;
  
      SurfaceData* exitSurfaceData = interfaces->physicsSurfaceProps->getSurfaceData(exitTrace.surface.surfaceProps);
  
      float damageModifier = 0.16f;
      float penetrationModifier = (enterSurfaceData->penetrationmodifier + exitSurfaceData->penetrationmodifier) / 2.0f;
  
      if (enterSurfaceData->material == 71 || enterSurfaceData->material == 89) {
          damageModifier = 0.05f;
          penetrationModifier = 3.0f;
      } else if (enterTrace.contents >> 3 & 1 || enterTrace.surface.flags >> 7 & 1) {
          penetrationModifier = 1.0f;
      }
  
      if (enterSurfaceData->material == exitSurfaceData->material) {
          if (exitSurfaceData->material == 85 || exitSurfaceData->material == 87)
              penetrationModifier = 3.0f;
          else if (exitSurfaceData->material == 76)
              penetrationModifier = 2.0f;
      }
  
      damage -= 11.25f / penetration / penetrationModifier + damage * damageModifier + (exitTrace.endpos - enterTrace.endpos).squareLength() / 24.0f / penetrationModifier;
  
      result = exitTrace.endpos;
      return damage;
  }
  
  static bool canScan(Entity* entity, const Vector& destination, const WeaponInfo* weaponData, int minDamage, bool allowFriendlyFire) noexcept
  {
      if (!localPlayer)
          return false;
  
      float damage{ static_cast<float>(weaponData->damage) };
  
      Vector start{ localPlayer->getEyePosition() };
      Vector direction{ destination - start };
      direction /= direction.length();
  
      int hitsLeft = 4;
  
      while (damage >= 1.0f && hitsLeft) {
          Trace trace;
          interfaces->engineTrace->traceRay({ start, destination }, 0x4600400B, localPlayer.get(), trace);
  
          if (!allowFriendlyFire && trace.entity && trace.entity->isPlayer() && !localPlayer->isOtherEnemy(trace.entity))
              return false;
  
          if (trace.fraction == 1.0f)
              break;
  
          if (trace.entity == entity && trace.hitgroup > HitGroup::Generic && trace.hitgroup <= HitGroup::RightLeg) {
              damage = HitGroup::getDamageMultiplier(trace.hitgroup) * damage * powf(weaponData->rangeModifier, trace.fraction * weaponData->range / 500.0f);
  
              if (float armorRatio{ weaponData->armorRatio / 2.0f }; HitGroup::isArmored(trace.hitgroup, trace.entity->hasHelmet()))
                  damage -= (trace.entity->armor() < damage * armorRatio / 2.0f ? trace.entity->armor() * 4.0f : damage) * (1.0f - armorRatio);
  
              return damage >= minDamage;
          }
          const auto surfaceData = interfaces->physicsSurfaceProps->getSurfaceData(trace.surface.surfaceProps);
  
          if (surfaceData->penetrationmodifier < 0.1f)
              break;
  
          damage = handleBulletPenetration(surfaceData, trace, direction, start, weaponData->penetration, damage);
          hitsLeft--;
      }
      return false;
  }
  //-->
  	static void setRandomSeed(int seed) noexcept
  {
      using randomSeedFn = void(*)(int);
      static auto randomSeed{ reinterpret_cast<randomSeedFn>(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomSeed")) };
      randomSeed(seed);
  }
  
  static float getRandom(float min, float max) noexcept
  {
      using randomFloatFn = float(*)(float, float);
      static auto randomFloat{ reinterpret_cast<randomFloatFn>(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomFloat")) };
      return randomFloat(min, max);
  }
  
  //<--
      
  void Aimbot::run(UserCmd* cmd) noexcept
  {
      if (!localPlayer || localPlayer->nextAttack() > memory->globalVars->serverTime() || localPlayer->isDefusing() || localPlayer->waitForNoAttack())
          return;
  
      const auto activeWeapon = localPlayer->getActiveWeapon();
      if (!activeWeapon || !activeWeapon->clip())
          return;
  
      if (localPlayer->shotsFired() > 0 && !activeWeapon->isFullAuto())
          return;
  
      auto weaponIndex = getWeaponIndex(activeWeapon->itemDefinitionIndex2());
      if (!weaponIndex)
          return;
  
      auto weaponClass = getWeaponClass(activeWeapon->itemDefinitionIndex2());
      if (!config->aimbot[weaponIndex].enabled)
          weaponIndex = weaponClass;
  
      if (!config->aimbot[weaponIndex].enabled)
          weaponIndex = 0;
      
      //-->
      if (!(localPlayer->flags() & 1) && config->aimbot[weaponIndex].aimbotJumpCheck)
          return;
      //<--
  
      if (!config->aimbot[weaponIndex].betweenShots && activeWeapon->nextPrimaryAttack() > memory->globalVars->serverTime())
          return;
  
      if (!config->aimbot[weaponIndex].ignoreFlash && localPlayer->isFlashed())
          return;
  
      if (config->aimbot[weaponIndex].onKey) {
          if (!config->aimbot[weaponIndex].keyMode) {
              if (!GetAsyncKeyState(config->aimbot[weaponIndex].key))
                  return;
          } else {
              static bool toggle = true;
              if (GetAsyncKeyState(config->aimbot[weaponIndex].key) & 1)
                  toggle = !toggle;
              if (!toggle)
                  return;
          }
      }
  
      if (config->aimbot[weaponIndex].enabled && (cmd->buttons & UserCmd::IN_ATTACK || config->aimbot[weaponIndex].autoShot || config->aimbot[weaponIndex].aimlock) && activeWeapon->getInaccuracy() <= config->aimbot[weaponIndex].maxAimInaccuracy) {
  
          if (config->aimbot[weaponIndex].scopedOnly && activeWeapon->isSniperRifle() && !localPlayer->isScoped())
              return;
  
          auto bestFov = config->aimbot[weaponIndex].fov;
          Vector bestTarget{ };
          const auto localPlayerEyePosition = localPlayer->getEyePosition();
  	    
  
          const auto aimPunch = activeWeapon->requiresRecoilControl() ? localPlayer->getAimPunch() : Vector{ };
  
          for (int i = 1; i <= interfaces->engine->getMaxClients(); i++) {
              auto entity = interfaces->entityList->getEntity(i);
              if (!entity || entity == localPlayer.get() || entity->isDormant() || !entity->isAlive()
                  || !entity->isOtherEnemy(localPlayer.get()) && !config->aimbot[weaponIndex].friendlyFire || entity->gunGameImmunity())
                  continue;
  
              for (auto bone : { 8, 4, 3, 7, 6, 5 }) {
                  const auto bonePosition = entity->getBonePosition(config->aimbot[weaponIndex].bone > 1 ? 10 - config->aimbot[weaponIndex].bone : bone);
                  const auto angle = calculateRelativeAngle(localPlayerEyePosition, bonePosition, cmd->viewangles + aimPunch);
                  
                  const auto fov = std::hypot(angle.x, angle.y);
                  if (fov > bestFov)
                      continue;
  
                  if (!config->aimbot[weaponIndex].ignoreSmoke && memory->lineGoesThroughSmoke(localPlayerEyePosition, bonePosition, 1))
                      continue;
  
                  if (!entity->isVisible(bonePosition) && (config->aimbot[weaponIndex].visibleOnly || !canScan(entity, bonePosition, activeWeapon->getWeaponData(), config->aimbot[weaponIndex].killshot ? entity->health() : config->aimbot[weaponIndex].minDamage, config->aimbot[weaponIndex].friendlyFire)))
                      continue;
  
                  if (fov < bestFov) {
                      bestFov = fov;
                      bestTarget = bonePosition;
                  }
                  if (config->aimbot[weaponIndex].bone)
                      break;
              }
          }
  
          if (bestTarget.notNull()) {
              static Vector lastAngles{ cmd->viewangles };
              static int lastCommand{ };
  
              if (lastCommand == cmd->commandNumber - 1 && lastAngles.notNull() && config->aimbot[weaponIndex].silent)
                  cmd->viewangles = lastAngles;
  
              auto angle = calculateRelativeAngle(localPlayerEyePosition, bestTarget, cmd->viewangles + aimPunch);
              bool clamped{ false };
  
              if (std::abs(angle.x) > config->misc.maxAngleDelta || std::abs(angle.y) > config->misc.maxAngleDelta) {
                      angle.x = std::clamp(angle.x, -config->misc.maxAngleDelta, config->misc.maxAngleDelta);
                      angle.y = std::clamp(angle.y, -config->misc.maxAngleDelta, config->misc.maxAngleDelta);
                      clamped = true;
              }
              
              angle /= config->aimbot[weaponIndex].smooth;
              cmd->viewangles += angle;
              if (!config->aimbot[weaponIndex].silent)
                  interfaces->engine->setViewAngles(cmd->viewangles);
  
              if (config->aimbot[weaponIndex].autoScope && activeWeapon->nextPrimaryAttack() <= memory->globalVars->serverTime() && activeWeapon->isSniperRifle() && !localPlayer->isScoped())
                  cmd->buttons |= UserCmd::IN_ATTACK2;
  
              if (config->aimbot[weaponIndex].autoShot && activeWeapon->nextPrimaryAttack() <= memory->globalVars->serverTime() && !clamped && activeWeapon->getInaccuracy() <= config->aimbot[weaponIndex].maxShotInaccuracy)
                  cmd->buttons |= UserCmd::IN_ATTACK;
  
              if (clamped)
                  cmd->buttons &= ~UserCmd::IN_ATTACK;
  
              if (clamped || config->aimbot[weaponIndex].smooth > 1.0f) lastAngles = cmd->viewangles;
              else lastAngles = Vector{ };
  
              lastCommand = cmd->commandNumber;
          }
      }
    
  	//-->
      auto aimPunch = activeWeapon->requiresRecoilControl() ? localPlayer->getAimPunch() : Vector{ };
      if (config->aimbot[weaponIndex].standaloneRCS && !config->aimbot[weaponIndex].silent) {
          static Vector lastAimPunch{ };
          if (localPlayer->getShotsFired() > config->aimbot[weaponIndex].shotsFired) {
              setRandomSeed(*memory->predictionRandomSeed);
              Vector currentPunch{ lastAimPunch.x - aimPunch.x, lastAimPunch.y - aimPunch.y, 0 };
              if (config->aimbot[weaponIndex].randomRCS) {
                  currentPunch.x *= getRandom(config->aimbot[weaponIndex].recoilControlX, 1.f);
                  currentPunch.y *= getRandom(config->aimbot[weaponIndex].recoilControlY, 1.f);
              }
              else {
                  currentPunch.x *= config->aimbot[weaponIndex].recoilControlX;
                  currentPunch.y *= config->aimbot[weaponIndex].recoilControlY;
              }
              cmd->viewangles += currentPunch;
          }
          interfaces->engine->setViewAngles(cmd->viewangles);
          lastAimPunch = aimPunch;
      }
   	//<--
  }
  