2021-01-02 01:49:45 -05:00
# include "STDInclude.hpp"
2021-05-04 16:12:07 -04:00
# define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something)
2021-05-09 12:56:10 -04:00
# define SIGN(d) ((d > 0) - (d < 0))
2021-05-04 16:12:07 -04:00
2021-01-02 01:49:45 -05:00
namespace Components
{
2021-01-02 02:17:37 -05:00
XINPUT_STATE XInput : : xiStates [ XUSER_MAX_COUNT ] ;
2021-05-02 07:13:13 -04:00
XINPUT_STATE XInput : : lastXiState = { 0 } ;
2021-01-02 14:42:52 -05:00
int XInput : : xiPlayerNum = - 1 ;
2021-05-04 16:12:07 -04:00
std : : chrono : : milliseconds XInput : : timeAtFirstHeldMaxLookX = 0 ms ; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0)
2021-05-02 07:13:13 -04:00
bool XInput : : isHoldingMaxLookX = false ;
2021-05-04 15:45:47 -04:00
bool XInput : : isADS ;
2021-05-02 07:13:13 -04:00
2021-05-04 09:47:46 -04:00
float XInput : : lastMenuNavigationDirection = .0f ;
std : : chrono : : milliseconds XInput : : lastNavigationTime = 0 ms ;
std : : chrono : : milliseconds XInput : : msBetweenNavigations = 220 ms ;
2021-08-14 04:38:00 -04:00
// This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg
2021-05-02 07:13:13 -04:00
std : : vector < XInput : : ActionMapping > mappings = {
XInput : : ActionMapping ( XINPUT_GAMEPAD_A , " gostand " ) ,
2021-05-02 10:13:33 -04:00
XInput : : ActionMapping ( XINPUT_GAMEPAD_B , " stance " ) ,
2021-05-02 07:13:13 -04:00
XInput : : ActionMapping ( XINPUT_GAMEPAD_X , " usereload " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_Y , " weapnext " , false ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_LEFT_SHOULDER , " smoke " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_RIGHT_SHOULDER , " frag " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_LEFT_THUMB , " breath_sprint " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_RIGHT_THUMB , " melee " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_START , " togglemenu " , false ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_BACK , " scores " ) ,
2021-05-04 16:12:07 -04:00
XInput : : ActionMapping ( XINPUT_GAMEPAD_DPAD_LEFT , " actionslot 3 " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_DPAD_RIGHT , " actionslot 2 " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_DPAD_DOWN , " actionslot 1 " ) ,
XInput : : ActionMapping ( XINPUT_GAMEPAD_DPAD_UP , " actionslot 4 " ) ,
2021-05-02 07:13:13 -04:00
} ;
2021-08-14 04:38:00 -04:00
// Same thing
2021-05-04 09:47:46 -04:00
std : : vector < XInput : : MenuMapping > menuMappings = {
XInput : : MenuMapping ( XINPUT_GAMEPAD_A , Game : : keyNum_t : : K_KP_ENTER ) ,
XInput : : MenuMapping ( XINPUT_GAMEPAD_B , Game : : keyNum_t : : K_ESCAPE ) ,
XInput : : MenuMapping ( XINPUT_GAMEPAD_DPAD_RIGHT , Game : : keyNum_t : : K_KP_RIGHTARROW ) ,
XInput : : MenuMapping ( XINPUT_GAMEPAD_DPAD_LEFT , Game : : keyNum_t : : K_KP_LEFTARROW ) ,
XInput : : MenuMapping ( XINPUT_GAMEPAD_DPAD_UP , Game : : keyNum_t : : K_KP_UPARROW ) ,
XInput : : MenuMapping ( XINPUT_GAMEPAD_DPAD_DOWN , Game : : keyNum_t : : K_KP_DOWNARROW )
} ;
2021-05-02 07:13:13 -04:00
2021-08-14 04:38:00 -04:00
void XInput : : GetLeftStick01Value ( XINPUT_STATE * xiState , float & x , float & y ) {
GamepadStickTo01 ( xiState - > Gamepad . sThumbLX , XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , x ) ;
GamepadStickTo01 ( xiState - > Gamepad . sThumbLY , XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , y ) ;
2021-05-09 12:56:10 -04:00
}
2021-08-14 04:38:00 -04:00
void XInput : : GetRightStick01Value ( XINPUT_STATE * xiState , float & x , float & y ) {
GamepadStickTo01 ( xiState - > Gamepad . sThumbRX , XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE , x ) ;
GamepadStickTo01 ( xiState - > Gamepad . sThumbRY , XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE , y ) ;
}
void XInput : : GamepadStickTo01 ( SHORT value , SHORT deadzone , float & output01 ) {
float maxValue = ( float ) ( std : : numeric_limits < SHORT > ( ) . max ( ) - deadzone ) ;
output01 = abs ( value ) > deadzone ? ( value - deadzone * SIGN ( value ) ) / maxValue : .0f ;
// log2 allows for a more neat value curve from 0 to 1
// It is not functional yet, because I suck at maths
//float test = (log2(abs(output01) + 1.f) - 1.f) * SIGN(value);
2021-05-09 12:56:10 -04:00
}
2021-05-02 07:13:13 -04:00
void XInput : : Vibrate ( int leftVal , int rightVal )
{
// Create a Vibraton State
XINPUT_VIBRATION Vibration ;
// Zeroise the Vibration
ZeroMemory ( & Vibration , sizeof ( XINPUT_VIBRATION ) ) ;
// Set the Vibration Values
Vibration . wLeftMotorSpeed = leftVal ;
Vibration . wRightMotorSpeed = rightVal ;
// Vibrate the controller
XInputSetState ( xiPlayerNum , & Vibration ) ;
}
2021-01-02 02:17:37 -05:00
void XInput : : PollXInputDevices ( )
{
2021-01-02 14:42:52 -05:00
XInput : : xiPlayerNum = - 1 ;
2021-01-03 03:33:12 -05:00
for ( int i = XUSER_MAX_COUNT - 1 ; i > = 0 ; i - - )
2021-01-02 02:17:37 -05:00
{
2021-01-02 14:42:52 -05:00
if ( XInputGetState ( i , & xiStates [ i ] ) = = ERROR_SUCCESS )
XInput : : xiPlayerNum = i ;
2021-01-02 02:17:37 -05:00
}
}
__declspec ( naked ) void XInput : : CL_FrameStub ( )
{
__asm
{
// poll the xinput devices on every client frame
call XInput : : PollXInputDevices
// execute the code we patched over
sub esp , 0 Ch
push ebx
push ebp
push esi
// return back to original code
push 0x486976
retn
}
}
2021-01-02 17:48:48 -05:00
void XInput : : CL_GamepadMove ( int , Game : : usercmd_s * cmd )
2021-01-02 14:42:52 -05:00
{
if ( XInput : : xiPlayerNum ! = - 1 )
{
XINPUT_STATE * xiState = & xiStates [ xiPlayerNum ] ;
2021-05-02 07:13:13 -04:00
// Deadzones
2021-05-09 12:56:10 -04:00
float moveStickX , moveStickY ;
GetLeftStick01Value ( xiState , moveStickX , moveStickY ) ;
2021-05-04 09:54:12 -04:00
if ( moveStickX ! = 0 | | moveStickY ! = 0 ) {
// We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in
cmd - > rightmove = moveStickX * std : : numeric_limits < char > ( ) . max ( ) ;
cmd - > forwardmove = moveStickY * std : : numeric_limits < char > ( ) . max ( ) ;
}
2021-05-02 07:13:13 -04:00
bool pressingLeftTrigger = xiState - > Gamepad . bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false ;
if ( pressingLeftTrigger ! = XInput : : lastXiState . Gamepad . bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD )
2021-01-03 03:33:12 -05:00
{
2021-05-04 12:09:37 -04:00
if ( pressingLeftTrigger ) {
2021-05-04 15:45:47 -04:00
Command : : Execute ( " +speed_throw " ) ;
XInput : : isADS = true ;
2021-05-04 12:09:37 -04:00
}
else {
2021-05-04 15:45:47 -04:00
Command : : Execute ( " -speed_throw " ) ;
XInput : : isADS = false ;
2021-05-04 12:09:37 -04:00
}
2021-01-03 03:33:12 -05:00
}
2021-05-02 07:13:13 -04:00
bool pressingRightTrigger = xiState - > Gamepad . bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false ;
if ( pressingRightTrigger ! = XInput : : lastXiState . Gamepad . bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD )
2021-01-03 03:33:12 -05:00
{
2021-05-08 19:24:37 -04:00
if ( pressingRightTrigger ) {
2021-01-03 03:33:12 -05:00
Command : : Execute ( " +attack " ) ;
2021-05-08 19:24:37 -04:00
}
else {
2021-01-03 03:33:12 -05:00
Command : : Execute ( " -attack " ) ;
2021-05-08 19:24:37 -04:00
}
2021-01-03 03:33:12 -05:00
}
2021-05-02 07:13:13 -04:00
// Buttons (on/off) mappings
for ( size_t i = 0 ; i < mappings . size ( ) ; i + + )
2021-01-03 03:33:12 -05:00
{
2021-05-02 07:13:13 -04:00
auto mapping = mappings [ i ] ;
auto action = mapping . action ;
auto antiAction = mapping . action ;
if ( mapping . isReversible ) {
action = " + " + mapping . action ;
antiAction = " - " + mapping . action ;
}
else if ( mapping . wasPressed ) {
if ( xiState - > Gamepad . wButtons & mapping . input ) {
// Button still pressed, do not send info
}
else {
mappings [ i ] . wasPressed = false ;
}
continue ;
}
if ( xiState - > Gamepad . wButtons & mapping . input ) {
2021-05-02 10:13:33 -04:00
if ( mapping . spamWhenHeld | | ! mappings [ i ] . wasPressed ) {
Command : : Execute ( action . c_str ( ) ) ;
}
2021-05-02 07:13:13 -04:00
mappings [ i ] . wasPressed = true ;
}
else if ( mapping . isReversible & & mapping . wasPressed ) {
mappings [ i ] . wasPressed = false ;
Command : : Execute ( antiAction . c_str ( ) ) ;
}
2021-01-03 03:33:12 -05:00
}
2021-05-02 07:13:13 -04:00
memcpy ( & XInput : : lastXiState , xiState , sizeof XINPUT_STATE ) ;
2021-01-02 14:42:52 -05:00
}
}
__declspec ( naked ) void XInput : : CL_CreateCmdStub ( )
{
__asm
{
// do xinput!
push esi
push ebp
call XInput : : CL_GamepadMove
add esp , 8 h
// execute code we patched over
add esp , 4
fld st
pop ebx
// return back
push 0x5A6DBF
retn
}
}
2021-01-02 17:48:48 -05:00
__declspec ( naked ) void XInput : : MSG_WriteDeltaUsercmdKeyStub ( )
{
__asm
{
// fix stack pointer
add esp , 0 Ch
// put both forward move and rightmove values in the movement button
2021-05-02 07:13:13 -04:00
mov dl , byte ptr [ edi + 1 Ah ] // to_forwardMove
mov dh , byte ptr [ edi + 1 Bh ] // to_rightMove
mov [ esp + 30 h ] , dx // to_buttons
2021-01-02 17:48:48 -05:00
2021-05-02 07:13:13 -04:00
mov dl , byte ptr [ ebp + 1 Ah ] // from_forwardMove
mov dh , byte ptr [ ebp + 1 Bh ] // from_rightMove
2021-01-02 17:48:48 -05:00
2021-05-02 07:13:13 -04:00
mov [ esp + 2 Ch ] , dx // from_buttons
2021-01-02 17:48:48 -05:00
// return back
push 0x60E40E
retn
}
}
2021-01-02 20:06:40 -05:00
void XInput : : ApplyMovement ( Game : : msg_t * msg , int key , Game : : usercmd_s * from , Game : : usercmd_s * to )
{
char forward ;
char right ;
if ( Game : : MSG_ReadBit ( msg ) )
{
short movementBits = static_cast < short > ( key ^ Game : : MSG_ReadBits ( msg , 16 ) ) ;
forward = static_cast < char > ( movementBits ) ;
right = static_cast < char > ( movementBits > > 8 ) ;
}
else
{
forward = from - > forwardmove ;
right = from - > rightmove ;
}
2021-05-02 07:13:13 -04:00
2021-01-02 20:06:40 -05:00
to - > forwardmove = forward ;
to - > rightmove = right ;
}
2021-01-02 17:48:48 -05:00
__declspec ( naked ) void XInput : : MSG_ReadDeltaUsercmdKeyStub ( )
{
2021-01-02 18:37:46 -05:00
__asm
{
2021-01-02 20:06:40 -05:00
push ebx // to
push ebp // from
push edi // key
push esi // msg
call XInput : : ApplyMovement
add esp , 10 h
2021-01-02 18:37:46 -05:00
// return back
push 0x4921BF
ret
}
}
2021-01-02 17:48:48 -05:00
2021-01-02 18:37:46 -05:00
__declspec ( naked ) void XInput : : MSG_ReadDeltaUsercmdKeyStub2 ( )
{
__asm
{
2021-01-02 20:06:40 -05:00
push ebx // to
push ebp // from
push edi // key
push esi // msg
call XInput : : ApplyMovement
add esp , 10 h
2021-01-02 18:37:46 -05:00
// return back
push 3
push esi
push 0x492085
ret
}
2021-01-02 17:48:48 -05:00
}
2021-05-04 09:47:46 -04:00
void XInput : : MenuNavigate ( ) {
Game : : menuDef_t * menuDef = Game : : Menu_GetFocused ( Game : : uiContext ) ;
if ( menuDef ) {
PollXInputDevices ( ) ;
if ( XInput : : xiPlayerNum ! = - 1 )
{
XINPUT_STATE * xiState = & xiStates [ xiPlayerNum ] ;
// Up/Down
float moveStickY = abs ( xiState - > Gamepad . sThumbLY ) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState - > Gamepad . sThumbLY / ( float ) std : : numeric_limits < SHORT > ( ) . max ( ) : .0f ;
std : : chrono : : milliseconds now = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) ;
std : : chrono : : milliseconds timeSinceLastNavigation = now - lastNavigationTime ;
bool canNavigate = timeSinceLastNavigation > msBetweenNavigations ;
if ( moveStickY > .0f ) {
if ( canNavigate | | SIGN ( moveStickY ) ! = SIGN ( lastMenuNavigationDirection ) ) {
Game : : Menu_SetPrevCursorItem ( Game : : uiContext , menuDef , 1 ) ;
lastMenuNavigationDirection = moveStickY ;
lastNavigationTime = now ;
}
}
else if ( moveStickY < .0f ) {
if ( canNavigate | | SIGN ( moveStickY ) ! = SIGN ( lastMenuNavigationDirection ) ) {
Game : : Menu_SetNextCursorItem ( Game : : uiContext , menuDef , 1 ) ;
lastMenuNavigationDirection = moveStickY ;
lastNavigationTime = now ;
}
}
else {
lastMenuNavigationDirection = .0f ;
}
for ( size_t i = 0 ; i < menuMappings . size ( ) ; i + + )
{
MenuMapping mapping = menuMappings [ i ] ;
if ( mapping . wasPressed ) {
if ( xiState - > Gamepad . wButtons & mapping . input ) {
// Button still pressed, do not send info
}
else {
menuMappings [ i ] . wasPressed = false ;
}
}
2021-05-04 12:09:37 -04:00
else if ( xiState - > Gamepad . wButtons & mapping . input ) {
2021-05-04 09:47:46 -04:00
Game : : UI_KeyEvent ( 0 , mapping . keystroke , 1 ) ;
menuMappings [ i ] . wasPressed = true ;
}
}
}
}
}
2021-05-08 19:24:37 -04:00
int XInput : : unk_CheckKeyHook ( int localClientNum , Game : : keyNum_t keyCode ) {
if ( XInput : : xiPlayerNum ! = - 1 )
{
XINPUT_STATE * xiState = & xiStates [ xiPlayerNum ] ;
if ( keyCode = = Game : : keyNum_t : : K_MOUSE2 ) {
bool pressingLeftTrigger = xiState - > Gamepad . bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false ;
if ( pressingLeftTrigger ! = XInput : : lastXiState . Gamepad . bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD )
{
if ( pressingLeftTrigger ) {
return 1 ;
}
else {
return 0 ;
}
}
}
}
Utils : : Hook : : Call < int ( int , Game : : keyNum_t ) > ( 0x48B2D0 ) ( localClientNum , keyCode ) ;
}
2021-05-04 12:09:37 -04:00
void XInput : : MouseOverride ( Game : : clientActive_t * clientActive , float * mx , float * my ) {
XInput : : CL_GetMouseMovementCl ( clientActive , mx , my ) ;
if ( XInput : : xiPlayerNum ! = - 1 )
{
XINPUT_STATE * xiState = & xiStates [ xiPlayerNum ] ;
2021-05-04 16:12:07 -04:00
float viewSensitivityMultiplier = Dvar : : Var ( " xpad_sensitivity " ) . get < float > ( ) * XINPUT_SENSITIVITY_MULTIPLIER ;
float lockedSensitivityMultiplier = Dvar : : Var ( " xpad_early_multiplier " ) . get < float > ( ) ;
float generalXSensitivityMultiplier = Dvar : : Var ( " xpad_horizontal_multiplier " ) . get < float > ( ) ;
float generalYSensitivityMultiplier = Dvar : : Var ( " xpad_vertical_multiplier " ) . get < float > ( ) ;
std : : chrono : : milliseconds msBeforeUnlockingSensitivity = std : : chrono : : milliseconds ( Dvar : : Var ( " xpad_early_time " ) . get < int > ( ) ) ;
2021-05-09 12:56:10 -04:00
float viewStickX , viewStickY ;
GetRightStick01Value ( xiState , viewStickX , viewStickY ) ;
2021-05-04 12:09:37 -04:00
2021-08-14 04:38:00 -04:00
# ifdef DEBUG
Components : : Logger : : Print ( " X:%f \n Y:%f \n (holdingMaxX: %d) \n " , viewStickX , viewStickY , XInput : : isHoldingMaxLookX ) ;
# endif
2021-05-04 12:09:37 -04:00
// Gamepad horizontal acceleration on view
2021-08-14 04:38:00 -04:00
if ( abs ( viewStickX ) > 0.80f ) {
2021-05-04 12:09:37 -04:00
if ( ! XInput : : isHoldingMaxLookX ) {
XInput : : isHoldingMaxLookX = true ;
XInput : : timeAtFirstHeldMaxLookX = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) ;
}
else {
std : : chrono : : milliseconds hasBeenHoldingLeftXForMs = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) - XInput : : timeAtFirstHeldMaxLookX ;
# ifdef STEP_SENSITIVITY
2021-05-04 16:12:07 -04:00
if ( hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity ) {
viewStickX * = lockedSensitivityMultiplier ;
2021-05-04 12:09:37 -04:00
}
# else
2021-05-04 16:12:07 -04:00
float coeff = std : : clamp ( hasBeenHoldingLeftXForMs . count ( ) / ( float ) msBeforeUnlockingSensitivity . count ( ) , 0.0F , 1.0F ) ;
viewStickX * = lockedSensitivityMultiplier + coeff * ( 1.0f - lockedSensitivityMultiplier ) ;
2021-05-04 12:09:37 -04:00
# endif
}
}
else {
XInput : : isHoldingMaxLookX = false ;
XInput : : timeAtFirstHeldMaxLookX = 0 ms ;
2021-05-09 12:56:10 -04:00
viewStickX * = lockedSensitivityMultiplier ;
2021-08-14 04:38:00 -04:00
Components : : Logger : : Print ( " multiplier will be %f \n " , lockedSensitivityMultiplier ) ;
2021-05-04 12:09:37 -04:00
}
2021-05-04 15:45:47 -04:00
float adsMultiplier = 1.0f ;
auto ps = & clientActive - > snap . ps ;
// DO NOT use clientActive->usingAds ! It only works for toggle ADS
if ( Game : : PM_IsAdsAllowed ( ps ) & & XInput : : isADS ) {
2021-05-04 16:12:07 -04:00
adsMultiplier = Dvar : : Var ( " xpad_ads_multiplier " ) . get < float > ( ) ;
2021-05-04 15:45:47 -04:00
}
2021-05-04 12:09:37 -04:00
if ( viewStickX ! = 0 | | viewStickY ! = 0 ) {
2021-05-04 15:45:47 -04:00
* ( my ) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier ;
* ( mx ) = - viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier ;
2021-05-04 12:09:37 -04:00
}
2021-05-08 19:24:37 -04:00
// Handling killstreaks
bool pressingRightTrigger = xiState - > Gamepad . bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false ;
if ( pressingRightTrigger ! = XInput : : lastXiState . Gamepad . bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD )
{
bool * isInPredator = reinterpret_cast < bool * > ( 0x8EE3B8 ) ;
if ( pressingRightTrigger ) {
Utils : : Hook : : Set ( 0xA1C4F4 , Game : : LOC_SEL_INPUT_CONFIRM ) ;
if ( * isInPredator ) {
// Yea, that's how we boost
// Command::execute is sync by default so the predator event gets fired properly
Command : : Execute ( " +attack " ) ;
Command : : Execute ( " -attack " ) ;
}
}
}
2021-05-04 12:09:37 -04:00
}
}
// Game -> Client DLL
__declspec ( naked ) void CL_GetMouseMovementStub ( )
{
__asm
{
push edx ;
push ecx ;
push eax ;
call XInput : : MouseOverride ;
add esp , 0xC ;
ret ;
}
}
// Client DLL -> Game
void XInput : : CL_GetMouseMovementCl ( Game : : clientActive_t * result , float * mx , float * my )
{
__asm
{
push ebx ;
push ecx ;
push edx ;
mov eax , result ;
mov ecx , mx ;
mov edx , my ;
mov ebx , 5 A60E0h ;
call ebx ;
pop edx ;
pop ecx ;
pop ebx ;
}
}
2021-01-02 01:49:45 -05:00
XInput : : XInput ( )
{
2021-01-02 18:37:46 -05:00
// poll xinput devices every client frame
2021-01-02 02:17:37 -05:00
Utils : : Hook ( 0x486970 , XInput : : CL_FrameStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2021-01-02 14:42:52 -05:00
2021-01-02 18:37:46 -05:00
// use the xinput state when creating a usercmd
2021-01-02 14:42:52 -05:00
Utils : : Hook ( 0x5A6DB9 , XInput : : CL_CreateCmdStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2021-01-02 17:48:48 -05:00
// package the forward and right move components in the move buttons
Utils : : Hook ( 0x60E38D , XInput : : MSG_WriteDeltaUsercmdKeyStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2021-01-02 20:06:40 -05:00
// send two bytes for sending movement data
Utils : : Hook : : Set < BYTE > ( 0x60E501 , 16 ) ;
Utils : : Hook : : Set < BYTE > ( 0x60E5CD , 16 ) ;
2021-01-02 17:48:48 -05:00
2021-05-04 09:42:22 -04:00
// make sure to parse the movement data properly and apply it
2021-01-02 20:06:40 -05:00
Utils : : Hook ( 0x492127 , XInput : : MSG_ReadDeltaUsercmdKeyStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
Utils : : Hook ( 0x492009 , XInput : : MSG_ReadDeltaUsercmdKeyStub2 , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2021-05-09 12:56:10 -04:00
2021-05-04 12:09:37 -04:00
Utils : : Hook ( 0x5A617D , CL_GetMouseMovementStub , HOOK_CALL ) . install ( ) - > quick ( ) ;
2021-05-08 19:24:37 -04:00
Utils : : Hook ( 0x5A6816 , CL_GetMouseMovementStub , HOOK_CALL ) . install ( ) - > quick ( ) ;
Utils : : Hook ( 0x5A6829 , unk_CheckKeyHook , HOOK_CALL ) . install ( ) - > quick ( ) ;
2021-05-04 12:09:37 -04:00
2021-05-09 12:56:10 -04:00
Game : : Dvar_RegisterFloat ( " xpad_sensitivity " , 1.9f , 0.1f , 10.0f , Game : : DVAR_FLAG_SAVED , " View sensitivity for XInput-compatible gamepads " ) ;
2021-08-14 04:38:00 -04:00
Game : : Dvar_RegisterInt ( " xpad_early_time " , 130 , 0 , 1000 , Game : : DVAR_FLAG_SAVED , " Time (in milliseconds) of reduced view sensitivity " ) ;
2021-05-09 12:56:10 -04:00
Game : : Dvar_RegisterFloat ( " xpad_early_multiplier " , 0.25f , 0.01f , 1.0f , Game : : DVAR_FLAG_SAVED , " By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick " ) ;
2021-05-04 16:12:07 -04:00
Game : : Dvar_RegisterFloat ( " xpad_horizontal_multiplier " , 1.5f , 1.0f , 20.0f , Game : : DVAR_FLAG_SAVED , " Horizontal view sensitivity multiplier " ) ;
Game : : Dvar_RegisterFloat ( " xpad_vertical_multiplier " , 0.8f , 1.0f , 20.0f , Game : : DVAR_FLAG_SAVED , " Vertical view sensitivity multiplier " ) ;
2021-05-09 12:56:10 -04:00
Game : : Dvar_RegisterFloat ( " xpad_ads_multiplier " , 0.7f , 0.1f , 1.0f , Game : : DVAR_FLAG_SAVED , " By how much the view sensitivity is multiplied when aiming down the sights. " ) ;
2021-05-04 12:09:37 -04:00
2021-05-04 09:42:22 -04:00
PollXInputDevices ( ) ;
if ( xiPlayerNum > = 0 ) {
Vibrate ( 3000 , 3000 ) ;
}
2021-05-04 09:47:46 -04:00
Scheduler : : OnFrame ( MenuNavigate ) ;
2021-01-02 01:49:45 -05:00
}
}