Esp stuff

This commit is contained in:
julianacat 2017-08-07 23:03:52 -05:00
parent ac2bf238b8
commit 53ca178872
2 changed files with 177 additions and 93 deletions

View File

@ -14,8 +14,10 @@ namespace hacks { namespace shared { namespace bunnyhop {
// Var for user settings
CatVar enabled(CV_SWITCH, "bhop_enabled", "0", "Bunnyhop", "Enable Bunnyhop. All extra features like autojump and perfect jump limit were temporary removed.");
//CatVar perfect_jump_limit(CV_INT, "bhop_enabled", "0", "Bunnyhop", "Enable Bunnyhop. All extra features like autojump and perfect jump limit were temporary removed.");
int iTicksLastJump = 0;
static int ticks_last_jump = 0;
//static int perfect_jumps = 0;
// Function called by game for movement
void CreateMove() {
@ -26,26 +28,22 @@ void CreateMove() {
// Check if there is usercommands
if (!g_pUserCmd->command_number) return;
// Check if local player is airborne, if true then return
//if (CE_INT(g_pLocalPlayer->entity, netvar.movetype) == MOVETYPE_FLY) return;
// Grab netvar for flags from the local player
int flags = CE_INT(g_pLocalPlayer->entity, netvar.iFlags);
// var for "if on ground" from the flags netvar
bool ground = (flags & (1 << 0));
bool ground = CE_INT(g_pLocalPlayer->entity, netvar.iFlags) & (1 << 0);
// Var for if the player is pressing jump
bool jump = (g_pUserCmd->buttons & IN_JUMP);
// Check if player is not on the ground and player is holding their jump key
if (!ground && jump) {
// If the ticks since last jump are greater or equal to 7, then force the player to stop jumping
// If the ticks since last jump are greater or equal to 9, then force the player to stop jumping
// The bot disables jump untill player hits the ground or lets go of jump
if (iTicksLastJump++ >= 9) g_pUserCmd->buttons = g_pUserCmd->buttons &~ IN_JUMP;
if (ticks_last_jump++ >= 9) {
g_pUserCmd->buttons = g_pUserCmd->buttons &~ IN_JUMP;
}
}
// If the players jump cmd has been used, then we reset our var
if (!jump) iTicksLastJump = 0;
if (!jump) ticks_last_jump = 0;
// Finish the function with return
return;

View File

@ -50,11 +50,25 @@ CatVar proj_esp(CV_SWITCH, "esp_proj", "1", "Projectile ESP", "Projectile ESP");
CatVar entity_model(CV_SWITCH, "esp_model_name", "0", "Model name ESP", "Model name esp (DEBUG ONLY)");
CatVar item_weapon_spawners(CV_SWITCH, "esp_weapon_spawners", "1", "Show weapon spawners", "TF2C deathmatch weapon spawners");
CatVar item_adrenaline(CV_SWITCH, "esp_item_adrenaline", "0", "Show Adrenaline", "TF2C adrenaline pills");
static CatVar box_healthbar(CV_SWITCH, "esp_box_healthbar", "1", "Box Healthbar");
static CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bone ID's");
static CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size");
static CatEnum esp_box_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" });
static CatVar esp_box_text_position(esp_box_text_position_enum, "esp_box_text_position", "0", "Text position", "Defines text position");
static CatVar box_nodraw(CV_SWITCH, "esp_box_nodraw", "0", "Invisible 2D Box", "Don't draw 2D box");
static CatVar box_expand(CV_INT, "esp_box_expand", "0", "Expand 2D Box", "Expand 2D box by N units");
static CatVar box_corners(CV_SWITCH, "esp_box_corners", "1", "Box Corners");
static CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP");
// Storage arrays for keeping strings and other data
std::mutex threadsafe_mutex;
std::array<ESPData, 2048> data;
// Storage vars for entities that need to be re-drawn
std::vector<int> entities_need_repaint {};
std::mutex entities_need_repaint_mutex {};
// Function to reset entitys strings
void ResetEntityStrings() {
for (auto& i : data) {
i.string_count = 0;
@ -63,10 +77,12 @@ void ResetEntityStrings() {
}
}
// Sets an entitys esp color
void SetEntityColor(CachedEntity* entity, const rgba_t& color) {
data[entity->m_IDX].color = color;
}
// Use to add a esp string to an entity
void AddEntityString(CachedEntity* entity, const std::string& string, const rgba_t& color) {
ESPData& entity_data = data[entity->m_IDX];
if (entity_data.string_count >= 15) return;
@ -77,28 +93,20 @@ void AddEntityString(CachedEntity* entity, const std::string& string, const rgba
}
std::vector<int> entities_need_repaint {};
std::mutex entities_need_repaint_mutex {};
static CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size");
// Function to draw box corners
void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, bool transparent) {
const rgba_t& black = transparent ? colors::Transparent(colors::black) : colors::black;
const int size = box_corner_size;
// Black corners
// Top Left
drawgl::FilledRect(minx, miny, size, 3, black);
drawgl::FilledRect(minx, miny + 3, 3, size - 3, black);
// Top Right
drawgl::FilledRect(maxx - size + 1, miny, size, 3, black);
drawgl::FilledRect(maxx - 3 + 1, miny + 3, 3, size - 3, black);
// Bottom Left
drawgl::FilledRect(minx, maxy - 3, size, 3, black);
drawgl::FilledRect(minx, maxy - size, 3, size - 3, black);
// Bottom Right
drawgl::FilledRect(maxx - size + 1, maxy - 3, size, 3, black);
drawgl::FilledRect(maxx - 2, maxy - size, 3, size - 3, black);
@ -118,33 +126,54 @@ void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, boo
drawgl::Line(maxx - 1, maxy - 2, 0, -(size - 2), color);
}
// Function called on create move
void CreateMove() {
if (!enabled) return;
std::lock_guard<std::mutex> esp_lock(threadsafe_mutex);
int limit;
static int max_clients = g_IEngine->GetMaxClients();
ResetEntityStrings();
entities_need_repaint.clear();
limit = HIGHEST_ENTITY;
if (!buildings && !proj_esp && !item_esp) limit = min(max_clients, HIGHEST_ENTITY);
{
// Check usersettings if enabled
if (!enabled) return;
// Something
std::lock_guard<std::mutex> esp_lock(threadsafe_mutex);
ResetEntityStrings(); // Clear any strings entities have
entities_need_repaint.clear(); // Clear data on entities that need redraw
// TODO, Find the benefit of using max clients with this logic
// Get max clients and
static int max_clients = g_IEngine->GetMaxClients();
int limit = HIGHEST_ENTITY;
// If not using any other special esp, we lower the min to the max clients
if (!buildings && !proj_esp && !item_esp)
limit = min(max_clients, HIGHEST_ENTITY);
{ // I still dont understand the purpose of prof_section and surrounding in brackets
PROF_SECTION(CM_ESP_EntityLoop);
// Loop through entities
for (int i = 0; i < limit; i++) {
// Get an entity from the loop tick and process it
CachedEntity* ent = ENTITY(i);
ProcessEntity(ent);
// Dont know what this check is for
if (data[i].string_count) {
// Set entity color
SetEntityColor(ent, colors::EntityF(ent));
// If snow distance, add string here
if (show_distance) {
AddEntityString(ent, format((int)(ENTITY(i)->m_flDistance / 64 * 1.22f), 'm'));
}
}
// No idea, this is confusing
if (data[ent->m_IDX].needs_paint) entities_need_repaint.push_back(ent->m_IDX);
}
}
}
// Function called on draw
void Draw() {
std::lock_guard<std::mutex> esp_lock(threadsafe_mutex);
if (!enabled) return;
@ -153,43 +182,34 @@ void Draw() {
}
}
static CatEnum esp_box_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" });
static CatVar esp_box_text_position(esp_box_text_position_enum, "esp_box_text_position", "0", "Text position", "Defines text position");
static CatVar box_nodraw(CV_SWITCH, "esp_box_nodraw", "0", "Invisible 2D Box", "Don't draw 2D box");
static CatVar box_expand(CV_INT, "esp_box_expand", "0", "Expand 2D Box", "Expand 2D box by N units");
static CatVar box_corners(CV_SWITCH, "esp_box_corners", "1", "Box Corners");
static CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP");
// TODO, Unknown, find what this does
const Vector dims_player[] = { { -16, -16, -4 }, { 16, 16, 72 } };
// Draw a box around a player
void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int health, int healthmax) {
PROF_SECTION(PT_esp_drawbox);
Vector so, omin, omax, smin, smax;
float height, width;
bool cloak;
int min_x, min_y, max_x, max_y, hbh;
rgba_t hp, border;
PROF_SECTION(PT_esp_drawbox); // Unknown
// Potentially un-used vars
//Vector so, omin, omax, smin, smax;
//float height, width;
// Check if ent is bad to prevent crashes
if (CE_BAD(ent)) return;
// Get collision center, max, and mins
const Vector& origin = RAW_ENT(ent)->GetCollideable()->GetCollisionOrigin();
Vector mins = RAW_ENT(ent)->GetCollideable()->OBBMins() + origin;
Vector maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs() + origin;
cloak = (ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent);
//if (!a) return;
//logging::Info("%f %f", so.x, so.y);
// Unknown
data.at(ent->m_IDX).esp_origin.Zero();
Vector points_r[8];
Vector points[8];
bool set, success;
float x, y, z;
set = false;
success = true;
// Create a array for storing box points
Vector points_r[8]; // World vectors
Vector points[8]; // Screen vectors
// If user setting for box expnad is true, spread the max and mins
if (box_expand) {
const float& exp = (float)box_expand;
maxs.x += exp;
@ -200,9 +220,10 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int
mins.z -= exp;
}
x = maxs.x - mins.x;
y = maxs.y - mins.y;
z = maxs.z - mins.z;
// Create points for the box based on max and mins
float x = maxs.x - mins.x;
float y = maxs.y - mins.y;
float z = maxs.z - mins.z;
points_r[0] = mins;
points_r[1] = mins + Vector(x, 0, 0);
points_r[2] = mins + Vector(x, y, 0);
@ -211,15 +232,20 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int
points_r[5] = mins + Vector(x, 0, z);
points_r[6] = mins + Vector(x, y, z);
points_r[7] = mins + Vector(0, y, z);
success = true;
// Check if any point of the box isnt on the screen
bool success = true;
for (int i = 0; i < 8; i++) {
if (!draw::WorldToScreen(points_r[i], points[i])) success = false;
}
// If a point isnt on the screen, return here
if (!success) return;
max_x = -1;
max_y = -1;
min_x = 65536;
min_y = 65536;
// Get max and min of the box using the newly created screen vector
int max_x = -1;
int max_y = -1;
int min_x = 65536;
int min_y = 65536;
for (int i = 0; i < 8; i++) {
if (points[i].x > max_x) max_x = points[i].x;
if (points[i].y > max_y) max_y = points[i].y;
@ -227,14 +253,7 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int
if (points[i].y < min_y) min_y = points[i].y;
}
/*if (box_expand) {
const float& exp = (float)box_expand;
max_x += exp;
max_y += exp;
min_x -= exp;
min_y -= exp;
}*/
// Put Text on the position with a switch
switch ((int)esp_box_text_position) {
case 0: { // TOP RIGHT
data.at(ent->m_IDX).esp_origin = Vector(max_x + 2, min_y, 0);
@ -251,10 +270,16 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int
data.at(ent->m_IDX).esp_origin = Vector(min_x, max_y, 0);
}
}
border = cloak ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a);
// Depending on whether the player is cloaked, we change the color acordingly
bool border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a);
// If box nodraw isnt true, we can draw our box
if (!box_nodraw) {
// With box corners, we draw differently
if (box_corners)
BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f));
// Otherwise, we just do simple draw funcs
else {
drawgl::Rect(min_x, min_y, max_x - min_x, max_y - min_y, border);
drawgl::Rect(min_x + 1, min_y + 1, max_x - min_x - 2, max_y - min_y - 2, clr);
@ -262,19 +287,21 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int
}
}
// If healthbar is enabled, create one here
if (healthbar) {
hp = colors::Transparent(colors::Health(health, healthmax), clr.a);
hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f);
rgba_t hp = colors::Transparent(colors::Health(health, healthmax), clr.a);
int hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f);
drawgl::Rect(min_x - 7, min_y, 7, max_y - min_y, border);
drawgl::FilledRect(min_x - 6, max_y - hbh - 1, 5, hbh, hp);
}
}
// Used to process entities from CreateMove
void _FASTCALL ProcessEntity(CachedEntity* ent) {
if (!enabled) return;
if (CE_BAD(ent)) return;
if (!enabled) return; // Esp enable check
if (CE_BAD(ent)) return; // CE_BAD check to prevent crashes
int string_count_backup, level, pclass, *weapon_list, handle, eid;
int string_count_backup, *weapon_list, handle, eid;
bool shown;
player_info_s info;
powerup_type power;
@ -282,6 +309,7 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
const char* weapon_name;
ESPData& espdata = data[ent->m_IDX];
// Entity esp
if (entity_info) {
AddEntityString(ent, format(RAW_ENT(ent)->GetClientClass()->m_pNetworkName, " [", ent->m_iClassID, "]"));
if (entity_id) {
@ -293,13 +321,18 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
}
}
// Projectile esp
if (ent->m_Type == ENTITY_PROJECTILE && proj_esp && (ent->m_bEnemy || (teammates && !proj_enemy))) {
// Rockets
if (ent->m_iClassID == CL_CLASS(CTFProjectile_Rocket) || ent->m_iClassID == CL_CLASS(CTFProjectile_SentryRocket)) {
if (proj_rockets) {
if ((int)proj_rockets != 2 || ent->m_bCritProjectile) {
AddEntityString(ent, "[ ==> ]");
}
}
// Pills/Stickys
} else if (ent->m_iClassID == CL_CLASS(CTFGrenadePipebombProjectile)) {
switch (CE_INT(ent, netvar.iPipeType)) {
case 0:
@ -312,6 +345,8 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
if ((int)proj_stickies == 2 && !ent->m_bCritProjectile) break;
AddEntityString(ent, "[ {*} ]");
}
// Huntsman
} else if (ent->m_iClassID == CL_CLASS(CTFProjectile_Arrow)) {
if ((int)proj_arrows != 2 || ent->m_bCritProjectile) {
AddEntityString(ent, "[ >>---> ]");
@ -319,6 +354,7 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
}
}
// Hl2DM dropped item esp
IF_GAME (IsHL2DM()) {
if (item_esp && item_dropped_weapons) {
if (CE_BYTE(ent, netvar.hOwner) == (unsigned char)-1) {
@ -341,10 +377,15 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
}
}
// Tank esp
if (ent->m_iClassID == CL_CLASS(CTFTankBoss) && tank) {
AddEntityString(ent, "Tank");
// Dropped weapon esp
} else if (ent->m_iClassID == CL_CLASS(CTFDroppedWeapon) && item_esp && item_dropped_weapons) {
AddEntityString(ent, format("WEAPON ", RAW_ENT(ent)->GetClientClass()->GetName()));
// MVM Money esp
} else if (ent->m_iClassID == CL_CLASS(CCurrencyPack) && item_money) {
if (CE_BYTE(ent, netvar.bDistributed)) {
if (item_money_red) {
@ -353,24 +394,40 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
} else {
AddEntityString(ent, "$$$");
}
// Other item esp
} else if (ent->m_ItemType != ITEM_NONE && item_esp) {
// TODO, what does shown var do
shown = false;
// Health pack esp
if (item_health_packs && (ent->m_ItemType >= ITEM_HEALTH_SMALL && ent->m_ItemType <= ITEM_HEALTH_LARGE || ent->m_ItemType == ITEM_HL_BATTERY)) {
if (ent->m_ItemType == ITEM_HEALTH_SMALL) AddEntityString(ent, "[+]");
if (ent->m_ItemType == ITEM_HEALTH_MEDIUM) AddEntityString(ent, "[++]");
if (ent->m_ItemType == ITEM_HEALTH_LARGE) AddEntityString(ent, "[+++]");
if (ent->m_ItemType == ITEM_HL_BATTERY) AddEntityString(ent, "[Z]");
// TF2C Adrenaline esp
} else if (item_adrenaline && ent->m_ItemType == ITEM_TF2C_PILL) {
AddEntityString(ent, "[a]");
// Ammo pack esp
} else if (item_ammo_packs && ent->m_ItemType >= ITEM_AMMO_SMALL && ent->m_ItemType <= ITEM_AMMO_LARGE) {
if (ent->m_ItemType == ITEM_AMMO_SMALL) AddEntityString(ent, "{i}");
if (ent->m_ItemType == ITEM_AMMO_MEDIUM) AddEntityString(ent, "{ii}");
if (ent->m_ItemType == ITEM_AMMO_LARGE) AddEntityString(ent, "{iii}");
// Powerup esp
} else if (item_powerups && ent->m_ItemType >= ITEM_POWERUP_FIRST && ent->m_ItemType <= ITEM_POWERUP_LAST) {
AddEntityString(ent, format(powerups[ent->m_ItemType - ITEM_POWERUP_FIRST], " PICKUP"));
// TF2C weapon spawner esp
} else if (item_weapon_spawners && ent->m_ItemType >= ITEM_TF2C_W_FIRST && ent->m_ItemType <= ITEM_TF2C_W_LAST) {
AddEntityString(ent, format(tf2c_weapon_names[ent->m_ItemType - ITEM_TF2C_W_FIRST], " SPAWNER"));
if (CE_BYTE(ent, netvar.bRespawning)) AddEntityString(ent, "-- RESPAWNING --");
// Halloween spell esp
} else if (item_spellbooks && (ent->m_ItemType == ITEM_SPELL || ent->m_ItemType == ITEM_SPELL_RARE)) {
if (ent->m_ItemType == ITEM_SPELL) {
AddEntityString(ent, "Spell", colors::green);
@ -378,48 +435,77 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
AddEntityString(ent, "Rare Spell", colors::FromRGBA8(139, 31, 221, 255));
}
}
// Building esp
} else if (ent->m_Type == ENTITY_BUILDING && buildings) {
// Check if enemy building
if (!ent->m_bEnemy && !teammates) return;
level = CE_INT(ent, netvar.iUpgradeLevel);
const std::string& name = (ent->m_iClassID == CL_CLASS(CObjectTeleporter) ? "Teleporter" : (ent->m_iClassID == CL_CLASS(CObjectSentrygun) ? "Sentry Gun" : "Dispenser"));
if (legit && ent->m_iTeam != g_pLocalPlayer->team) {
/*if (ent->m_lLastSeen > v_iLegitSeenTicks->GetInt()) {
// TODO maybe...
/*if (legit && ent->m_iTeam != g_pLocalPlayer->team) {
if (ent->m_lLastSeen > v_iLegitSeenTicks->GetInt()) {
return;
}*/
}
if (show_name || show_class) AddEntityString(ent, format("LV ", level, ' ', name));
}*/
// Make a name for the building based on the building type and level
if (show_name || show_class) {
const std::string& name = (ent->m_iClassID == CL_CLASS(CObjectTeleporter) ? "Teleporter" : (ent->m_iClassID == CL_CLASS(CObjectSentrygun) ? "Sentry Gun" : "Dispenser"));'
int level = CE_INT(ent, netvar.iUpgradeLevel);
AddEntityString(ent, format("LV ", level, ' ', name));
}
// If show health is true, then add a string with the health
if (show_health) {
AddEntityString(ent, format(ent->m_iHealth, '/', ent->m_iMaxHealth, " HP"), colors::Health(ent->m_iHealth, ent->m_iMaxHealth));
}
// Set the entity to repaint
espdata.needs_paint = true;
return;
// Player esp
} else if (ent->m_Type == ENTITY_PLAYER && ent->m_bAlivePlayer) {
// Local player handling
if (!(local_esp && g_IInput->CAM_IsThirdPerson()) &&
ent->m_IDX == g_IEngine->GetLocalPlayer()) return;
pclass = CE_INT(ent, netvar.iClass);
// Get player class
int pclass = CE_INT(ent, netvar.iClass);
// Attempt to get player info, and if cant, return
if (!g_IEngine->GetPlayerInfo(ent->m_IDX, &info)) return;
// If target is enemy, always show powerups, if player is teammate, show powerups
// only if bTeammatePowerup or bTeammates is true
// TODO, check if u can just use "ent->m_bEnemy" instead of m_iTeam
// Legit mode handling
if (legit && ent->m_iTeam != g_pLocalPlayer->team && playerlist::IsDefault(info.friendsID)) {
if (IsPlayerInvisible(ent)) return;
if (vischeck && !ent->IsVisible()) return;
/*if (ent->m_lLastSeen > (unsigned)v_iLegitSeenTicks->GetInt()) {
return;
}*/
if (IsPlayerInvisible(ent)) return; // Invis check
if (vischeck && !ent->IsVisible()) return; // Vis check
// TODO, maybe...
//if (ent->m_lLastSeen > (unsigned)v_iLegitSeenTicks->GetInt()) return;
}
// Powerup handling
if (powerup_esp) {
power = GetPowerupOnPlayer(ent);
if (power != not_powerup)
AddEntityString(ent, format("^ ", powerups[power], " ^"));
}
// Dont understand reasoning for this check
if (ent->m_bEnemy || teammates || !playerlist::IsDefault(info.friendsID)) {
// Playername
if (show_name)
AddEntityString(ent, std::string(info.name));
// Player class
if (show_class) {
if (pclass > 0 && pclass < 10)
AddEntityString(ent, classes[pclass - 1]);
}
#ifdef IPC_ENABLED
// ipc bot esp
if (show_bot_id && ipc::peer && ent != LOCAL_E) {
for (unsigned i = 1; i < cat_ipc::max_peers; i++) {
if (!ipc::peer->memory->peer_data[i].free && ipc::peer->memory->peer_user_data[i].friendid == info.friendsID) {
@ -429,6 +515,7 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
}
}
#endif
// Health esp
if (show_health) {
AddEntityString(ent, format(ent->m_iHealth, '/', ent->m_iMaxHealth, " HP"), colors::Health(ent->m_iHealth, ent->m_iMaxHealth));
}
@ -493,8 +580,7 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) {
return;
}
}
static CatVar box_healthbar(CV_SWITCH, "esp_box_healthbar", "1", "Box Healthbar");
static CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bone ID's");
const std::string bonenames_leg_r[] = { "bip_foot_R", "bip_knee_R", "bip_hip_R" };
const std::string bonenames_leg_l[] = { "bip_foot_L", "bip_knee_L", "bip_hip_L" };