#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <xs>
#define PLUGIN "Strafe Hack Detector"
#define VERSION "0.0.3"
#define AUTHOR "Mistrick"
#pragma semicolon 1
#define bit_contain(%0,%1) (%0 & (%1) == %1)
#define bit_not_contain(%0,%1) (~%0 & (%1) == %1)
const PITCH = 0;
const YAW = 1;
const ROLL = 2;
enum
{
RIGHT,
LEFT
};
#define MIN_BUTTONS_TICKS 2
#define MAX_WARN_OVER_VALUE 32
enum Keys
{
_KeyW, _KeyA, _KeyS, _KeyD
};
new g_eButtons[Keys] =
{
IN_FORWARD, IN_MOVELEFT, IN_BACK, IN_MOVERIGHT
};
new g_eKeyName[Keys][] =
{
"[W]", "", "[A]", "[D]"
};
new g_iButtonsTicks[33][Keys];
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
register_forward(FM_CmdStart, "FM_CmdStart_Pre", false);
}
public FM_CmdStart_Pre(id, uc_handle, seed)
{
if(!is_user_alive(id)) return FMRES_IGNORED;
static _old_buttons[33], Float:_old_view_angles[33][3];
new buttons = get_uc(uc_handle, UC_Buttons);
new Float:view_angles[3]; get_uc(uc_handle, UC_ViewAngles, view_angles);
new Float:diff[3]; xs_vec_sub(view_angles, _old_view_angles[id], diff);
new Float:forward_move; get_uc(uc_handle, UC_ForwardMove, forward_move);
new Float:side_move; get_uc(uc_handle, UC_SideMove, side_move);
// Detect invise strafes
// if don't press +strafe
if(!null_vec(diff))
{
// forward_move with out button
// diff[PITCH] for -mlook
if(forward_move != 0.0 && bit_not_contain(buttons, IN_FORWARD|IN_BACK) && diff[PITCH] != 0.0)
{
reduce_speed(id);
// console_print(id, "forward move w/o buttons, %f, %d, %d", forward_move, buttons & IN_FORWARD, buttons & IN_BACK);
}
// side_move with out button
if(side_move != 0.0 && bit_not_contain(buttons, IN_MOVERIGHT|IN_MOVELEFT))
{
reduce_speed(id);
// console_print(id, "side move w/o buttons, %f, %d, %d", side_move, buttons & IN_MOVERIGHT, buttons & IN_MOVELEFT);
}
}
static _warn_over_value[33];
new Float:value = floatsqroot(forward_move * forward_move + side_move * side_move);
new Float:maxspeed; pev(id, pev_maxspeed, maxspeed);
if(value > maxspeed)
{
if(++_warn_over_value[id] >= MAX_WARN_OVER_VALUE)
{
reduce_speed(id);
// console_print(id, "value %f, maxspeed %f, fw %f, sd %f", value, maxspeed, forward_move, side_move);
}
}
else
{
_warn_over_value[id] = 0;
}
/*
if(bit_contain(buttons, IN_MOVERIGHT|IN_MOVELEFT))
{
console_print(id, "moveleft + moveright, sd %f", side_move);
}
*/
//
static Float:_old_yaw_diff[33];
static _old_turn[33];
static _old_changed_turn[33];
new Float:yaw_diff = diff[YAW];
if(yaw_diff >= 180.0) yaw_diff -= 360.0;
if(yaw_diff < -180.0) yaw_diff += 360.0;
new changed_turn;
// right move
if(yaw_diff < 0.0)
{
if(_old_turn[id] == LEFT)
{
changed_turn = true;
}
_old_turn[id] = RIGHT;
}
else // left move
{
if(_old_turn[id] == RIGHT)
{
changed_turn = true;
}
_old_turn[id] = LEFT;
}
_old_yaw_diff[id] = yaw_diff;
// check buttons press ticks
new current_const;
for(new Keys:key; key < Keys; key++)
{
current_const = g_eButtons[key];
if(buttons & current_const && ~_old_buttons[id] & current_const)
{
// console_print(id, "pressed button %s, fw %f, sd %f", g_eKeyName[key], forward_move, side_move);
if(value == maxspeed)
{
reduce_speed(id);
// console_print(id, "strafe helper?");
}
}
if(buttons & current_const)
{
g_iButtonsTicks[id][key]++;
}
if(~buttons & current_const && _old_buttons[id] & current_const)
{
// console_print(id, "Key %s released, ticks %d", g_eKeyName[key], g_iButtonsTicks[id][key]);
if(g_iButtonsTicks[id][key] <= MIN_BUTTONS_TICKS)
{
reduce_speed(id);
// console_print(id, "Small button ticks, key %s, ticks %d", g_eKeyName[key], g_iButtonsTicks[id][key]);
}
g_iButtonsTicks[id][key] = 0;
/*
if(changed_turn)
{
console_print(id, "released button %s with changed turn, fw %f, sd %f", g_eKeyName[key], forward_move, side_move);
}
if(_old_changed_turn[id])
{
console_print(id, "released button %s with old changed turn, fw %f, sd %f", g_eKeyName[key], forward_move, side_move);
}
*/
}
}
_old_buttons[id] = buttons;
_old_view_angles[id] = view_angles;
_old_changed_turn[id] = changed_turn;
return FMRES_IGNORED;
}
reduce_speed(id)
{
new Float:velocity[3];
pev(id, pev_velocity, velocity);
velocity[0] *= 0.2;
velocity[1] *= 0.2;
set_pev(id, pev_velocity, velocity);
}
null_vec(Float:vec[3])
{
return (vec[0] == 0.0 && vec[1] == 0.0) ? true : false;
}