Code:
#include <amxmodx>
#include <cstrike>
#include <engine>
#include <fun>
#include <fakemeta>
#include <hamsandwich>
#include <xs>
#define PLUGIN "KnifeBot Detector"
#define VERSION "1.0"
#define AUTHOR "Mistrick"
#pragma semicolon 1
#define INIT_RECHECK 0.5
#define CHECK_TIME 0.15
#define RECHECK_TIME 3.0
#define MAX_WARNIGNS 3
#define BOT_RECREATE 20
new const DEFAULT_NAME[][] =
{
"Saint Sinner",
"BOT?",
"nOOB"
}
DEFAULT_NAME[random_num(0, sizeof DEFAULT_NAME - 1)]
#define CHANGE_BOT_TEAM
#define RANDOM_ANGLES
#define LOGFILE "knifebot_detector.log"
new g_BotIndex, g_bInChecking, g_Target, g_iAttacks, g_iAttacks2, g_iWarnings[33];
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
RegisterHam(Ham_Spawn, "player", "Ham_PlayerSpawn_Post", .Post = true);
RegisterHam(Ham_Player_PreThink, "player", "Ham_PlayerPreThink_Pre", .Post = false);
register_forward(FM_AddToFullPack, "FM_AddToFullPack_Pre", ._post = false);
}
CreateBot()
{
if(!DEFAULT_NAME[0])
{
set_fail_state("Set own valid bot name!");
}
//new name[32]; get_user_name(0, name, charsmax(name));
new bot = g_BotIndex = engfunc(EngFunc_CreateFakeClient, DEFAULT_NAME);
if(!bot)
{
return PLUGIN_HANDLED;
}
engfunc(EngFunc_FreeEntPrivateData, bot);
dllfunc(MetaFunc_CallGameEntity, "player", bot);
bot_settings(bot);
new reject_reason[128];
dllfunc(DLLFunc_ClientConnect, bot, DEFAULT_NAME, "127.0.0.1", reject_reason);
if(!is_user_connected(bot))
{
return PLUGIN_HANDLED;
}
dllfunc(DLLFunc_ClientPutInServer, bot);
cs_set_user_team(bot, CS_TEAM_SPECTATOR);
ExecuteHamB(Ham_CS_RoundRespawn, bot);
set_user_rendering(g_BotIndex, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, 0);
return PLUGIN_HANDLED;
}
bot_settings(id)
{
set_user_info(id, "bottomcolor", "6");
set_user_info(id, "model", "gordon");
set_user_info(id, "rate", "8000");
set_user_info(id, "cl_updaterate", "45");
set_user_info(id, "cl_lw", "1");
set_user_info(id, "cl_lc", "1");
set_user_info(id, "cl_dlmax", "128");
set_user_info(id, "_ah", "0");
set_user_info(id, "_cl_autowepswitch", "1");
set_user_info(id, "_vgui_menus", "0");
}
public client_putinserver(id)
{
if(is_user_bot(id)) return;
static connections = 0;
g_iWarnings[id] = 0;
if(!(connections % BOT_RECREATE))
{
if(is_user_connected(g_BotIndex))
{
server_cmd("kick #%d", get_user_userid(g_BotIndex));
server_exec();
}
CreateBot();
}
connections++;
}
public Ham_PlayerSpawn_Post(id)
{
if(!is_user_alive(id) || id == g_BotIndex || !is_user_connected(g_BotIndex)) return HAM_IGNORED;
if(!task_exists(id))
{
InitChecking(id);
}
return HAM_IGNORED;
}
public Ham_PlayerPreThink_Pre(id)
{
if(g_Target != id || get_user_weapon(id) != CSW_KNIFE) return HAM_IGNORED;
new buttons = pev(id, pev_button);
new oldbuttons = pev(id, pev_oldbuttons);
if(buttons & IN_ATTACK && ~oldbuttons & IN_ATTACK)
{
g_iAttacks++;
}
if(buttons & IN_ATTACK2 && ~oldbuttons & IN_ATTACK2)
{
g_iAttacks2++;
}
return HAM_IGNORED;
}
public FM_AddToFullPack_Pre(es, e, ent, host, flags, player, pSet)
{
if(player && host != ent && host != g_Target && ent == g_BotIndex)
{
forward_return(FMV_CELL, 0);
return FMRES_SUPERCEDE;
}
return FMRES_IGNORED;
}
public InitChecking(id)
{
if(g_bInChecking)
{
//server_print("init recheck %d", id);
set_task(INIT_RECHECK, "InitChecking", id);
return;
}
if(is_near_other_player(id))
{
//server_print("near other player, init recheck %d", id);
set_task(RECHECK_TIME, "InitChecking", id);
return;
}
g_bInChecking = true;
g_Target = id;
set_task(0.1, "StartCheckKB", id);
//server_print("init check %d", id);
}
is_near_other_player(id)
{
new players[32], pnum;
get_players(players, pnum, "ac");
new alive = is_user_alive(id);
for(new i, player; i < pnum; i++)
{
player = players[i];
if(player != id && alive && get_entity_distance(id, player) < 80)
{
return true;
}
}
return false;
}
public StartCheckKB(id)
{
if(!is_user_alive(id))
{
reset_checking();
return;
}
//server_print("start check %d", id);
if(!is_user_alive(g_BotIndex))
{
ExecuteHam(Ham_CS_RoundRespawn, g_BotIndex);
}
set_pev(g_BotIndex, pev_health, 10.0);
set_pev(g_BotIndex, pev_solid, SOLID_SLIDEBOX);
set_pev(g_BotIndex, pev_takedamage, DAMAGE_NO);
#if defined CHANGE_BOT_TEAM
switch(cs_get_user_team(id))
{
case CS_TEAM_T: cs_set_user_team(g_BotIndex, CS_TEAM_CT, CS_CT_GIGN);
case CS_TEAM_CT: cs_set_user_team(g_BotIndex, CS_TEAM_T, CS_T_TERROR);
}
#endif // CHANGE_BOT_TEAM
new Float:origin[3];
#if defined RANDOM_ANGLES
get_front_origin(id, random_float(48.0, 54.0), origin, random_float(-45.0, 45.0));
#else
get_front_origin(id, random_float(48.0, 54.0), origin);
#endif // RANDOM_ANGLES
engfunc(EngFunc_SetOrigin, g_BotIndex, origin);
set_task(CHECK_TIME, "EndCheckKB", id);
}
public EndCheckKB(id)
{
if(!is_user_alive(id))
{
reset_checking();
return;
}
//server_print("ent check %d", id);
new warn_hp = get_user_health(g_BotIndex) != 10000;
if(g_iAttacks || g_iAttacks2/* || warn_hp*/)
{
UTIL_LogUser(id, "Add warn: atk1 %d, atk2 %d, hp %d", g_iAttacks, g_iAttacks2, warn_hp);
server_print("add warn, hp warn %d, a1 %d, a2 %d, id %d", warn_hp, g_iAttacks, g_iAttacks2, id);
if(++g_iWarnings[id] >= MAX_WARNIGNS)
{
g_iWarnings[id] = 0;
Panishment(id);
}
}
else if(g_iWarnings[id])
{
g_iWarnings[id]--;
}
reset_checking();
set_task(random_float(RECHECK_TIME - 0.5, RECHECK_TIME + 0.5), "InitChecking", id);
}
reset_checking()
{
g_bInChecking = false;
g_Target = 0;
g_iAttacks = 0;
g_iAttacks2 = 0;
set_pev(g_BotIndex, pev_solid, SOLID_NOT);
set_pev(g_BotIndex, pev_takedamage, DAMAGE_AIM);
#if defined CHANGE_BOT_TEAM
cs_set_user_team(g_BotIndex, CS_TEAM_SPECTATOR);
#endif // CHANGE_BOT_TEAM
}
Panishment(id)
{
new name[32]; get_user_name(id, name, charsmax(name));
client_print(0, print_chat, "[ANTI KNIFEBOT] Noob %s use KnifeBot!", name);
UTIL_LogUser(id, "Player panished for knife bot!");
server_cmd("fb_ban 10080 #%i KnifeBot Hack!",get_user_userid(id));
}
stock get_front_origin(id, Float:dist, Float:origin[3], Float:angle = 0.0)
{
new iVectorStart[3]; get_user_origin(id, iVectorStart, 1);
new iVectorEnd[3]; get_user_origin(id, iVectorEnd, 3);
new Float:fVectorStart[3]; IVecFVec(iVectorStart, fVectorStart);
new Float:fVectorEnd[3]; IVecFVec(iVectorEnd, fVectorEnd);
new Float:fAddVec[3]; xs_vec_sub(fVectorEnd, fVectorStart, fAddVec);
fAddVec[2] = 0.0;
xs_vec_normalize(fAddVec, fAddVec);
new Float: velocity[3];
pev(id, pev_velocity, velocity);
velocity[2] = 0.0;
new Float:vec_angle = vectors_angle(fAddVec, velocity);
if(vec_angle < 80.0)
{
dist += vector_length(velocity) * CHECK_TIME;
}
xs_vec_mul_scalar(fAddVec, dist, fAddVec);
if(angle != 0.0)
{
fAddVec = vec_rotation(fAddVec, angle);
}
pev(id, pev_origin, origin);
xs_vec_add(origin, fAddVec, origin);
}
stock Float:vec_rotation(Float:vec[3], Float:angle)
{
new Float:out[3];
out[0] = vec[0] * floatcos(angle, degrees) - vec[1] * floatsin(angle, degrees);
out[1] = vec[0] * floatsin(angle, degrees) + vec[1] * floatcos(angle, degrees);
out[2] = vec[2];
return out;
}
stock Float:vectors_angle(Float:v1[3], Float:v2[3])
{
return floatacos( (v1[0]*v2[0]+v1[1]*v2[1])/(floatsqroot(v1[0]*v1[0]+v1[1]*v1[1])*floatsqroot(v2[0]*v2[0]+v2[1]*v2[1])), degrees);
}
stock UTIL_LogUser(const id, const szCvar[], any:...)
{
static log_file[128];
if(!log_file[0])
{
get_localinfo("amxx_logs", log_file, charsmax(log_file));
format(log_file, charsmax(log_file), "/%s/%s", log_file, LOGFILE);
}
new file;
if( (file = fopen(log_file, "a")) )
{
new name[32], authid[32], ip[32], time[22];
new message[128]; vformat(message, charsmax(message), szCvar, 3);
get_user_name(id, name, charsmax(name));
get_user_authid(id, authid, charsmax(authid));
get_user_ip(id, ip, charsmax(ip), 1);
get_time("%m/%d/%Y - %H:%M:%S", time, charsmax(time));
fprintf(file, "L %s: <%s><%s><%s> %s^n", time, name, authid, ip, message);
fclose(file);
}
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1048\\ f0\\ fs16 \n\\ par }
*/