Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2016 lines
66 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Joystick handling function
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "cbase.h"
  10. #include "basehandle.h"
  11. #include "utlvector.h"
  12. #include "cdll_client_int.h"
  13. #include "cdll_util.h"
  14. #include "kbutton.h"
  15. #include "usercmd.h"
  16. #include "iclientvehicle.h"
  17. #include "input.h"
  18. #include "iviewrender.h"
  19. #include "iclientmode.h"
  20. #include "convar.h"
  21. #include "hud.h"
  22. #include "vgui/ISurface.h"
  23. #include "vgui_controls/Controls.h"
  24. #include "vgui/Cursor.h"
  25. #include "tier0/icommandline.h"
  26. #include "inputsystem/iinputsystem.h"
  27. #include "inputsystem/ButtonCode.h"
  28. #include "math.h"
  29. #include "tier1/convar_serverbounded.h"
  30. #include "c_baseplayer.h"
  31. #include "ienginevgui.h"
  32. #include "inputsystem/iinputstacksystem.h"
  33. #if defined (CSTRIKE_DLL)
  34. #include "c_cs_player.h"
  35. #endif
  36. #if defined( _X360 )
  37. #include "xbox/xbox_win32stubs.h"
  38. #elif defined( _PS3 )
  39. #include "ps3/ps3_core.h"
  40. #include "ps3/ps3_win32stubs.h"
  41. #else
  42. #include "../common/xbox/xboxstubs.h"
  43. #endif
  44. #ifdef PORTAL2
  45. #include "radialmenu.h"
  46. #endif
  47. // memdbgon must be the last include file in a .cpp file!!!
  48. #include "tier0/memdbgon.h"
  49. // Control like a joystick
  50. #define JOY_ABSOLUTE_AXIS 0x00000000
  51. // Control like a mouse, spinner, trackball
  52. #define JOY_RELATIVE_AXIS 0x00000010
  53. // Set the joystick being force disabled just as we write the config
  54. // This allows us to chose this option in the menu with a controller without accidentally disabling our only mode of input
  55. void JoystickForceDisabled_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue );
  56. static ConVar joystick_force_disabled_set_from_options( "joystick_force_disabled_set_from_options", "1", FCVAR_ARCHIVE, "Sets controllers enabled/disabled just before the config is written.", JoystickForceDisabled_ChangeCallback );
  57. static ConVar joystick_force_disabled( "joystick_force_disabled", "1", FCVAR_ARCHIVE, "Prevents any and all joystick input for cases where a piece of hardware is incorrectly identified as a joystick an sends bad signals." );
  58. void JoystickForceDisabled_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue )
  59. {
  60. ConVarRef var( pConVar );
  61. if ( var.IsValid() && !var.GetBool() )
  62. {
  63. // Enabling joystick happens immediately, rather than being delayed
  64. if ( joystick_force_disabled.GetBool() )
  65. {
  66. joystick_force_disabled.SetValue( false );
  67. }
  68. }
  69. }
  70. static ConVar joy_variable_frametime( "joy_variable_frametime", IsGameConsole() ? "0" : "1", 0 );
  71. // Axis mapping
  72. static ConVar joy_name( "joy_name", "joystick", FCVAR_ARCHIVE );
  73. static ConVar joy_advanced( "joy_advanced", "0", FCVAR_ARCHIVE );
  74. static ConVar joy_advaxisx( "joy_advaxisx", "0", FCVAR_ARCHIVE );
  75. static ConVar joy_advaxisy( "joy_advaxisy", "0", FCVAR_ARCHIVE );
  76. static ConVar joy_advaxisz( "joy_advaxisz", "0", FCVAR_ARCHIVE );
  77. static ConVar joy_advaxisr( "joy_advaxisr", "0", FCVAR_ARCHIVE );
  78. static ConVar joy_advaxisu( "joy_advaxisu", "0", FCVAR_ARCHIVE );
  79. static ConVar joy_advaxisv( "joy_advaxisv", "0", FCVAR_ARCHIVE );
  80. // Basic "dead zone" and sensitivity
  81. static ConVar joy_forwardthreshold( "joy_forwardthreshold", "0.15", FCVAR_ARCHIVE );
  82. static ConVar joy_sidethreshold( "joy_sidethreshold", "0.15", FCVAR_ARCHIVE );
  83. static ConVar joy_pitchthreshold( "joy_pitchthreshold", "0.15", FCVAR_ARCHIVE );
  84. static ConVar joy_yawthreshold( "joy_yawthreshold", "0.15", FCVAR_ARCHIVE );
  85. static ConVar joy_forwardsensitivity( "joy_forwardsensitivity", "-1", FCVAR_ARCHIVE );
  86. static ConVar joy_sidesensitivity( "joy_sidesensitivity", "1", FCVAR_ARCHIVE );
  87. static ConVar joy_pitchsensitivity( "joy_pitchsensitivity", "-1", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "joystick pitch sensitivity", true, -5.0f, true, -0.1f );
  88. static ConVar joy_yawsensitivity( "joy_yawsensitivity", "-1", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "joystick yaw sensitivity", true, -5.0f, true, -0.1f );
  89. // Advanced sensitivity and response
  90. #ifdef _X360 //tmuaer
  91. static ConVar joy_response_move( "joy_response_move", "9", FCVAR_ARCHIVE, "'Movement' stick response mode: 0=Linear, 1=quadratic, 2=cubic, 3=quadratic extreme, 4=power function(i.e., pow(x,1/sensitivity)), 5=two-stage" );
  92. #else
  93. static ConVar joy_response_move( "joy_response_move", "1", FCVAR_ARCHIVE, "'Movement' stick response mode: 0=Linear, 1=quadratic, 2=cubic, 3=quadratic extreme, 4=power function(i.e., pow(x,1/sensitivity)), 5=two-stage" );
  94. #endif
  95. ConVar joy_response_move_vehicle("joy_response_move_vehicle", "6");
  96. static ConVar joy_response_look( "joy_response_look", "0", FCVAR_ARCHIVE, "'Look' stick response mode: 0=Default, 1=Acceleration Promotion" );
  97. static ConVar joy_response_look_pitch( "joy_response_look_pitch", "1", FCVAR_ARCHIVE, "'Look' stick response mode for pitch: 0=Default, 1=Acceleration Promotion" );
  98. static ConVar joy_lowend( "joy_lowend", "1", FCVAR_ARCHIVE );
  99. static ConVar joy_lowend_linear( "joy_lowend_linear", "0.55", FCVAR_ARCHIVE );
  100. static ConVar joy_lowmap( "joy_lowmap", "1", FCVAR_ARCHIVE );
  101. static ConVar joy_gamma( "joy_gamma", "0.2", FCVAR_ARCHIVE );
  102. static ConVar joy_accelscale( "joy_accelscale", "3.5", FCVAR_ARCHIVE);
  103. static ConVar joy_accelscalepoly( "joy_accelscalepoly", "0.4", FCVAR_ARCHIVE);
  104. static ConVar joy_accelmax( "joy_accelmax", "1.0", FCVAR_ARCHIVE);
  105. static ConVar joy_autoAimDampenMethod( "joy_autoAimDampenMethod", "0", FCVAR_ARCHIVE );
  106. static ConVar joy_autoaimdampenrange( "joy_autoaimdampenrange", "0", FCVAR_ARCHIVE, "The stick range where autoaim dampening is applied. 0 = off" );
  107. static ConVar joy_autoaimdampen( "joy_autoaimdampen", "0", FCVAR_ARCHIVE, "How much to scale user stick input when the gun is pointing at a valid target." );
  108. // smooth out of the auto-aim at this amount per second
  109. static ConVar joy_autoaim_dampen_smoothout_speed( "joy_autoaim_dampen_smoothout_speed", "0.25" ); // percentage per second. 0.5 == 50 percentage points per second
  110. static ConVar joy_curvepoint_1( "joy_curvepoint_1", "0.001", FCVAR_ARCHIVE, "", true, 0.001, true, 5 );
  111. static ConVar joy_curvepoint_2( "joy_curvepoint_2", "0.4", FCVAR_ARCHIVE, "", true, 0.001, true, 5 );
  112. static ConVar joy_curvepoint_3( "joy_curvepoint_3", "0.75", FCVAR_ARCHIVE, "", true, 0.001, true, 5 );
  113. static ConVar joy_curvepoint_4( "joy_curvepoint_4", "1", FCVAR_ARCHIVE, "", true, 0.001, true, 5 );
  114. static ConVar joy_curvepoint_end( "joy_curvepoint_end", "2", FCVAR_ARCHIVE, "", true, 0.001, true, 5 );
  115. static ConVar joy_vehicle_turn_lowend("joy_vehicle_turn_lowend", "0.7");
  116. static ConVar joy_vehicle_turn_lowmap("joy_vehicle_turn_lowmap", "0.4");
  117. static ConVar joy_sensitive_step0( "joy_sensitive_step0", "0.1", FCVAR_ARCHIVE);
  118. static ConVar joy_sensitive_step1( "joy_sensitive_step1", "0.4", FCVAR_ARCHIVE);
  119. static ConVar joy_sensitive_step2( "joy_sensitive_step2", "0.90", FCVAR_ARCHIVE);
  120. static ConVar joy_circle_correct( "joy_circle_correct", "1", FCVAR_ARCHIVE);
  121. // Misc
  122. static ConVar joy_diagonalpov( "joy_diagonalpov", "0", FCVAR_ARCHIVE, "POV manipulator operates on diagonal axes, too." );
  123. static ConVar joy_display_input("joy_display_input", "0", FCVAR_ARCHIVE);
  124. static ConVar joy_wwhack2( "joy_wingmanwarrior_turnhack", "0", FCVAR_ARCHIVE, "Wingman warrior hack related to turn axes." );
  125. ConVar joy_autosprint("joy_autosprint", "0", 0, "Automatically sprint when moving with an analog joystick" );
  126. static ConVar joy_inverty("joy_inverty", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Whether to invert the Y axis of the joystick for looking." );
  127. #if !defined ( CSTRIKE15 )
  128. static ConVar joy_inverty_default( "joy_inverty_default", "0", FCVAR_ARCHIVE_GAMECONSOLE ); // Extracted & saved from profile
  129. static ConVar joy_movement_stick_default( "joy_movement_stick_default", "0", FCVAR_ARCHIVE_GAMECONSOLE ); // Extracted & saved from profile
  130. #endif
  131. // XBox Defaults
  132. static ConVar joy_yawsensitivity_default( "joy_yawsensitivity_default", "-1.0", FCVAR_NONE );
  133. static ConVar joy_pitchsensitivity_default( "joy_pitchsensitivity_default", "-1.0", FCVAR_NONE );
  134. static ConVar sv_stickysprint_default( "sv_stickysprint_default", "0", FCVAR_NONE );
  135. static ConVar joy_lookspin_default( "joy_lookspin_default", "0.35", FCVAR_NONE );
  136. static ConVar joy_cfg_preset( "joy_cfg_preset", "1", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS );
  137. void joy_movement_stick_Callback( IConVar *var, const char *pOldString, float flOldValue )
  138. {
  139. if ( engine )
  140. {
  141. engine->ClientCmd_Unrestricted( "joyadvancedupdate silent\n" );
  142. }
  143. }
  144. static ConVar joy_movement_stick("joy_movement_stick", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Which stick controls movement : 0 = left stick, 1 = right stick, 2 = legacy controls", joy_movement_stick_Callback );
  145. static ConVar joy_xcontroller_cfg_loaded( "joy_xcontroller_cfg_loaded", "0", 0, "If 0, the 360controller.cfg file will be executed on startup & option changes." );
  146. ConVar joy_no_accel_jump( "joy_no_accel_jump", "0", FCVAR_ARCHIVE );
  147. // Motion controller
  148. static ConVar mc_dead_zone_radius( "mc_dead_zone_radius", "0.06", FCVAR_ARCHIVE, "0 to 0.9. 0 being just around the center of the screen and 1 being the edges of the screen.", true, 0.0f, true, 0.9f );
  149. static ConVar mc_accel_band_size( "mc_accel_band_size", "0.5", FCVAR_ARCHIVE, "Percentage of half the screen width or height.", true, 0.01f, true, 2.0f );
  150. static ConVar mc_max_yawrate( "mc_max_yawrate", "230.0", FCVAR_ARCHIVE, "(degrees/sec)", true, 10.0,true, 720.0 );
  151. static ConVar mc_max_pitchrate( "mc_max_pitchrate", "100.0", FCVAR_ARCHIVE, "(degrees/sec)", true, 10.0,true, 720.0 );
  152. static ConVar mc_turnPctPegged("mc_turnPctPegged", "1.0", FCVAR_DEVELOPMENTONLY, "pegged at above this amount" );
  153. static ConVar mc_turnPctPeggedMultiplier("mc_turnPctPeggedMultiplier", "1.0", FCVAR_DEVELOPMENTONLY, "speed multiplier when pegged" );
  154. static ConVar mc_turn_curve("mc_turn_curve", "0", FCVAR_DEVELOPMENTONLY, "What type of acceleration curve to use for turning.");
  155. static ConVar mc_screen_clamp( "mc_screen_clamp", "0.8f", FCVAR_DEVELOPMENTONLY, "Clamps the cursor to this much of the screen.");
  156. static ConVar mc_force_aim_x("mc_force_aim_x", "0", FCVAR_DEVELOPMENTONLY, "debug for testing player's aim");
  157. static ConVar mc_force_aim_y("mc_force_aim_y", "0", FCVAR_DEVELOPMENTONLY, "debug for testing player's aim");
  158. static ConVar mc_always_lock_ret_on_zoom( "mc_always_lock_ret_on_zoom", "1", FCVAR_DEVELOPMENTONLY, "Always lock the reticle when zoomed (even for partial zoom weapons)");
  159. static ConVar mc_max_dampening("mc_max_dampening", "0.9", FCVAR_DEVELOPMENTONLY, "dampening player's aim");
  160. static ConVar mc_dampening_blend_amount("mc_dampening_blend_amount", "0.0", FCVAR_DEVELOPMENTONLY, "dampening player's aim");
  161. static ConVar mc_max_turn_dampening("mc_max_turn_dampening", "0.8", FCVAR_DEVELOPMENTONLY, "dampening player's aim while scoped");
  162. static ConVar mc_turn_dampening_blend_amount("mc_turn_dampening_blend_amount", "0.02", FCVAR_DEVELOPMENTONLY, "dampening player's aim while scoped");
  163. static ConVar mc_zoom_out_cursor_offset_blend("mc_zoom_out_cursor_offset_blend", "0.05", FCVAR_DEVELOPMENTONLY, "0.0 means snap to the new amount.");
  164. static ConVar mc_zoomed_out_dead_zone_radius( "mc_zoomed_out_dead_zone_radius", "0.1", FCVAR_DEVELOPMENTONLY, "0 to 0.9. 0 being just around the center of the screen and 1 being the edges of the screen.", true, 0.0f, true, 0.9f );
  165. static ConVar mc_zoomed_aim_style("mc_zoomed_aim_style", "1", FCVAR_DEVELOPMENTONLY, "0-analog stick style. 1-pointer style.");
  166. extern ConVar lookspring;
  167. extern ConVar cl_forwardspeed;
  168. extern ConVar lookstrafe;
  169. extern ConVar in_joystick;
  170. extern ConVar_ServerBounded *m_pitch;
  171. extern ConVar l_pitchspeed;
  172. extern ConVar cl_sidespeed;
  173. extern ConVar cl_yawspeed;
  174. extern ConVar cl_pitchdown;
  175. extern ConVar cl_pitchup;
  176. extern ConVar cl_pitchspeed;
  177. #ifdef INFESTED_DLL
  178. extern ConVar asw_cam_marine_yaw;
  179. #endif
  180. extern ConVar cam_idealpitch;
  181. extern ConVar cam_idealyaw;
  182. extern ConVar thirdperson_platformer;
  183. extern ConVar thirdperson_screenspace;
  184. //-----------------------------------------------
  185. // Response curve function for the move axes
  186. //-----------------------------------------------
  187. static float ResponseCurve( int curve, float x, int axis, float sensitivity )
  188. {
  189. switch ( curve )
  190. {
  191. case 1:
  192. // quadratic
  193. if ( x < 0 )
  194. return -(x*x) * sensitivity;
  195. return x*x * sensitivity;
  196. case 2:
  197. // cubic
  198. return x*x*x*sensitivity;
  199. case 3:
  200. {
  201. // quadratic extreme
  202. float extreme = 1.0f;
  203. if ( fabs( x ) >= 0.95f )
  204. {
  205. extreme = 1.5f;
  206. }
  207. if ( x < 0 )
  208. return -extreme * x*x*sensitivity;
  209. return extreme * x*x*sensitivity;
  210. }
  211. case 4:
  212. {
  213. float flScale = sensitivity < 0.0f ? -1.0f : 1.0f;
  214. sensitivity = clamp( fabs( sensitivity ), 1.0e-8f, 1000.0f );
  215. float oneOverSens = 1.0f / sensitivity;
  216. if ( x < 0.0f )
  217. {
  218. flScale = -flScale;
  219. }
  220. float retval = clamp( powf( fabs( x ), oneOverSens ), 0.0f, 1.0f );
  221. return retval * flScale;
  222. }
  223. break;
  224. case 5:
  225. {
  226. float out = x;
  227. if( fabs(out) <= 0.6f )
  228. {
  229. out *= 0.5f;
  230. }
  231. out = out * sensitivity;
  232. return out;
  233. }
  234. break;
  235. case 6: // Custom for driving a vehicle!
  236. {
  237. if( axis == YAW )
  238. {
  239. // This code only wants to affect YAW axis (the left and right axis), which
  240. // is used for turning in the car. We fall-through and use a linear curve on
  241. // the PITCH axis, which is the vehicle's throttle. REALLY, these are the 'forward'
  242. // and 'side' axes, but we don't have constants for those, so we re-use the same
  243. // axis convention as the look stick. (sjb)
  244. float sign = 1;
  245. if( x < 0.0 )
  246. sign = -1;
  247. x = fabs(x);
  248. if( x <= joy_vehicle_turn_lowend.GetFloat() )
  249. x = RemapVal( x, 0.0f, joy_vehicle_turn_lowend.GetFloat(), 0.0f, joy_vehicle_turn_lowmap.GetFloat() );
  250. else
  251. x = RemapVal( x, joy_vehicle_turn_lowend.GetFloat(), 1.0f, joy_vehicle_turn_lowmap.GetFloat(), 1.0f );
  252. return x * sensitivity * sign;
  253. }
  254. //else
  255. // fall through and just return x*sensitivity below (as if using default curve)
  256. }
  257. //The idea is to create a max large walk zone surrounded by a max run zone.
  258. case 7:
  259. {
  260. float xAbs = fabs(x);
  261. if(xAbs < joy_sensitive_step0.GetFloat())
  262. {
  263. return 0;
  264. }
  265. else if (xAbs < joy_sensitive_step2.GetFloat())
  266. {
  267. return (85.0f/cl_forwardspeed.GetFloat()) * ((x < 0)? -1.0f : 1.0f);
  268. }
  269. else
  270. {
  271. return ((x < 0)? -1.0f : 1.0f);
  272. }
  273. }
  274. break;
  275. case 8: //same concept as above but with smooth speeds
  276. {
  277. float xAbs = fabs(x);
  278. if(xAbs < joy_sensitive_step0.GetFloat())
  279. {
  280. return 0;
  281. }
  282. else if (xAbs < joy_sensitive_step2.GetFloat())
  283. {
  284. float maxSpeed = (85.0f/cl_forwardspeed.GetFloat());
  285. float t = (xAbs-joy_sensitive_step0.GetFloat())
  286. / (joy_sensitive_step2.GetFloat()-joy_sensitive_step0.GetFloat());
  287. float speed = t*maxSpeed;
  288. return speed * ((x < 0)? -1.0f : 1.0f);
  289. }
  290. else
  291. {
  292. float maxSpeed = 1.0f;
  293. float minSpeed = (85.0f/cl_forwardspeed.GetFloat());
  294. float t = (xAbs-joy_sensitive_step2.GetFloat())
  295. / (1.0f-joy_sensitive_step2.GetFloat());
  296. float speed = t*(maxSpeed-minSpeed) + minSpeed;
  297. return speed * ((x < 0)? -1.0f : 1.0f);
  298. }
  299. }
  300. break;
  301. case 9: //same concept as above but with smooth speeds for walking and a hard speed for running
  302. {
  303. float xAbs = fabs(x);
  304. if(xAbs < joy_sensitive_step0.GetFloat())
  305. {
  306. return 0;
  307. }
  308. else if (xAbs < joy_sensitive_step1.GetFloat())
  309. {
  310. float maxSpeed = (85.0f/cl_forwardspeed.GetFloat());
  311. float t = (xAbs-joy_sensitive_step0.GetFloat())
  312. / (joy_sensitive_step1.GetFloat()-joy_sensitive_step0.GetFloat());
  313. float speed = t*maxSpeed;
  314. return speed * ((x < 0)? -1.0f : 1.0f);
  315. }
  316. else if (xAbs < joy_sensitive_step2.GetFloat())
  317. {
  318. return (85.0f/cl_forwardspeed.GetFloat()) * ((x < 0)? -1.0f : 1.0f);
  319. }
  320. else
  321. {
  322. return ((x < 0)? -1.0f : 1.0f);
  323. }
  324. }
  325. break;
  326. }
  327. // linear
  328. return x*sensitivity;
  329. }
  330. //-----------------------------------------------
  331. // If we have a valid autoaim target, dampen the
  332. // player's stick input if it is moving away from
  333. // the target.
  334. //
  335. // This assists the player staying on target.
  336. //-----------------------------------------------
  337. float CInput::AutoAimDampening( float x, int axis, float dist )
  338. {
  339. if ( joy_autoAimDampenMethod.GetInt() == 1 )
  340. {
  341. // disabled 6/29/15 -mtw
  342. /*
  343. // $FIXME(hpe) Split screen
  344. // Help the user stay on target if the feature is enabled and the user
  345. // is not making a gross stick movement.
  346. if ( joy_autoaimdampen.GetFloat() > 0.0f && fabs(x) < joy_autoaimdampenrange.GetFloat() )
  347. {
  348. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  349. if ( pLocalPlayer && pLocalPlayer->IsCursorOnAutoAimTarget() )
  350. {
  351. m_lastAutoAimValue = joy_autoaimdampen.GetFloat();
  352. return m_lastAutoAimValue;
  353. }
  354. }
  355. if ( m_lastAutoAimValue < 1.0f )
  356. {
  357. m_lastAutoAimValue += joy_autoaim_dampen_smoothout_speed.GetFloat() * gpGlobals->frametime;
  358. if ( m_lastAutoAimValue >= 1.0f )
  359. {
  360. m_lastAutoAimValue = 1.0f;
  361. }
  362. }
  363. */
  364. return m_lastAutoAimValue;// No dampening.
  365. }
  366. else
  367. {
  368. // Help the user stay on target if the feature is enabled and the user
  369. // is not making a gross stick movement.
  370. if ( joy_autoaimdampen.GetFloat() > 0.0f && fabs(x) < joy_autoaimdampenrange.GetFloat() )
  371. {
  372. // Get the player
  373. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  374. if ( pLocalPlayer )
  375. {
  376. // Get the autoaim target
  377. if ( pLocalPlayer->m_Local.m_bAutoAimTarget )
  378. {
  379. return joy_autoaimdampen.GetFloat();
  380. }
  381. }
  382. }
  383. }
  384. return 1.0f;// No dampening.
  385. }
  386. //-----------------------------------------------
  387. // This structure holds persistent information used
  388. // to make decisions about how to modulate analog
  389. // stick input.
  390. //-----------------------------------------------
  391. typedef struct
  392. {
  393. float envelopeScale[2];
  394. bool peggedAxis[2];
  395. bool axisPeggedDir[2];
  396. } envelope_t;
  397. envelope_t controlEnvelope[ MAX_SPLITSCREEN_PLAYERS ];
  398. static bool IsJoystickPegged( float input, float otherAxis )
  399. {
  400. #if defined( _X360 )
  401. static float fPower = 1.25f;
  402. #elif defined( _PS3 )
  403. static float fPower = 0.9f;
  404. #else
  405. static float fPower = 0.9f; // pc
  406. #endif
  407. float fMinimumVal = 0.01f; // accomodate dead zone
  408. float algorythmX = abs(input);
  409. float algorythmY = MAX( abs(otherAxis),fMinimumVal );
  410. #if defined( _PS3 )
  411. float fltempAlgorythmSample = MAX( algorythmX, algorythmY );
  412. #else
  413. float fltempAlgorythmSample = pow( pow(algorythmX,fPower)+pow(algorythmY,fPower),fPower);
  414. #endif
  415. #if defined( _X360 )
  416. float flJoyAddititiveDistComparison = 0.98f;
  417. #elif defined( _PS3 )
  418. float flJoyAddititiveDistComparison = 0.91f;
  419. #else
  420. float flJoyAddititiveDistComparison = 0.94f;
  421. #endif
  422. bool result = fltempAlgorythmSample >= flJoyAddititiveDistComparison;
  423. return result;
  424. }
  425. //-----------------------------------------------
  426. // Response curve function specifically for the
  427. // 'look' analog stick.
  428. //
  429. // when AXIS == YAW, otherAxisValue contains the
  430. // value for the pitch of the control stick, and
  431. // vice-versa.
  432. //-----------------------------------------------
  433. ConVar joy_pegged("joy_pegged", "0.75");// Once the stick is pushed this far, it's assumed pegged.
  434. ConVar joy_virtual_peg("joy_virtual_peg", "0");
  435. float CInput::ResponseCurveLookDefault( int nSlot, float x, int axis, float otherAxis, float dist, float frametime )
  436. {
  437. envelope_t &envelope = controlEnvelope[ MAX( nSlot, 0 ) ];
  438. float input = x;
  439. // float maxX = 1.0; used in prev algorithm
  440. float flJoyDist = dist;//MAX( dist, MIN( joy_pegged.GetFloat(), sqrt(x*x + otherAxis*otherAxis) ) );
  441. bool bPegged = ( flJoyDist >= joy_pegged.GetFloat() ) || IsJoystickPegged( x, otherAxis );
  442. // Make X positive to make things easier, just remember whether we have to flip it back!
  443. bool negative = false;
  444. if( x < 0.0f )
  445. {
  446. negative = true;
  447. x *= -1;
  448. }
  449. if ( otherAxis < 0.0f )
  450. {
  451. otherAxis *= -1;
  452. }
  453. if( axis == YAW && joy_virtual_peg.GetBool() )
  454. {
  455. if( x >= 0.95f )
  456. {
  457. // User has pegged the stick
  458. envelope.peggedAxis[axis] = true;
  459. envelope.axisPeggedDir[axis] = negative;
  460. }
  461. if( envelope.peggedAxis[axis] == true )
  462. {
  463. // User doesn't have the stick pegged on this axis, but they used to.
  464. // If the stick is physically pegged, pretend this axis is still pegged.
  465. if( bPegged && negative == envelope.axisPeggedDir[axis] )
  466. {
  467. // If the user still has the stick physically pegged and hasn't changed direction on
  468. // this axis, keep pretending they have the stick pegged on this axis.
  469. x = 1.0f;
  470. }
  471. else
  472. {
  473. envelope.peggedAxis[axis] = false;
  474. }
  475. }
  476. }
  477. // Perform the two-stage mapping.
  478. float tmpDist = dist;
  479. if( tmpDist > joy_lowend.GetFloat() || x > joy_lowend_linear.GetFloat() )
  480. {
  481. tmpDist = RemapValClamped( tmpDist, joy_lowend.GetFloat(), 1.0f, joy_lowmap.GetFloat(), 1.0f );
  482. // Accelerate.
  483. if( envelope.envelopeScale[axis] < 1.0f )
  484. {
  485. envelope.envelopeScale[axis] += ( frametime * joy_accelscale.GetFloat() );
  486. if( envelope.envelopeScale[axis] > 1.0f )
  487. {
  488. envelope.envelopeScale[axis] = 1.0f;
  489. }
  490. }
  491. float delta = tmpDist - joy_lowmap.GetFloat();
  492. tmpDist = joy_lowmap.GetFloat() + (delta * envelope.envelopeScale[axis]);
  493. }
  494. else
  495. {
  496. // Shut off acceleration
  497. envelope.envelopeScale[axis] = 0.0f;
  498. tmpDist = RemapValClamped( tmpDist, 0.0f, joy_lowend.GetFloat(), 0.0f, joy_lowmap.GetFloat() );
  499. if( tmpDist > 0.0f && joy_display_input.GetBool() )
  500. {
  501. Msg("AXIS == %d : 2: x = :%f, otherAxis = %f\n", axis, x, otherAxis );
  502. }
  503. }
  504. if ( dist > 0.01f )
  505. {
  506. float newX = x;
  507. if ( axis == YAW )
  508. {
  509. float input = x / dist;
  510. input = clamp( input, -1.0f, 1.0f );
  511. float theta = acos( input );
  512. newX = cos( theta ) * tmpDist;
  513. //Msg( "input: %f, theta:%f, x: %f\n", input, theta, newX );
  514. }
  515. else
  516. {
  517. float input = x / dist;
  518. input = clamp( input, -1.0f, 1.0f );
  519. float theta = asin( input );
  520. newX = sin( theta ) * tmpDist;
  521. //Msg( "input: %f, theta:%f, x: %f\n", input, theta, newX );
  522. }
  523. x = newX;
  524. }
  525. /*(
  526. // Perform the two-stage mapping.
  527. if( x > joy_lowend.GetFloat() )
  528. {
  529. float highmap = 1.0f - joy_lowmap.GetFloat();
  530. float xNormal = x - joy_lowend.GetFloat();
  531. float xNormalMax = maxX - joy_lowend.GetFloat();
  532. float factor = xNormal / ( 1.0f - joy_lowend.GetFloat() );
  533. float factorMax = xNormalMax / ( 1.0f - joy_lowend.GetFloat() );
  534. x = joy_lowmap.GetFloat() + (highmap * factor);
  535. maxX = joy_lowmap.GetFloat() + (highmap * factorMax);
  536. //if( x > 0.0f && joy_display_input.GetBool() )
  537. //{
  538. // Msg("AXIS == %d : 1a: x = :%f\n", axis, x );
  539. //}
  540. // Accelerate.
  541. if( envelope.envelopeScale[axis] < 1.0f )
  542. {
  543. envelope.envelopeScale[axis] += ( frametime * joy_accelscale.GetFloat() );
  544. if( envelope.envelopeScale[axis] > 1.0f )
  545. {
  546. envelope.envelopeScale[axis] = 1.0f;
  547. }
  548. }
  549. float delta = x - joy_lowmap.GetFloat();
  550. float deltaMax = maxX - joy_lowmap.GetFloat();
  551. x = joy_lowmap.GetFloat() + (delta * envelope.envelopeScale[axis]);
  552. maxX = joy_lowmap.GetFloat() + (deltaMax * envelope.envelopeScale[axis]);
  553. if( x > 0.0f && joy_display_input.GetBool() )
  554. {
  555. Msg("AXIS == %d : 1b: x = :%f, otherAxis = %f\n", axis, x, otherAxis );
  556. }
  557. }
  558. else
  559. {
  560. // Shut off acceleration
  561. envelope.envelopeScale[axis] = 0.0f;
  562. float factor = x / joy_lowend.GetFloat();
  563. x = (joy_lowmap.GetFloat() * factor);
  564. if( x > 0.0f && joy_display_input.GetBool() )
  565. {
  566. Msg("AXIS == %d : 2: x = :%f, otherAxis = %f\n", axis, x, otherAxis );
  567. }
  568. }
  569. */
  570. x *= AutoAimDampening( input, axis, dist );
  571. //float flDiagDiff = abs(x - otherAxis);
  572. //x *= MIN( maxX, 1+(otherAxis) );
  573. if( x > 0.0f && joy_display_input.GetBool() )
  574. {
  575. Msg("AXIS == %d : In:%f Out:%f Frametime:%f\n", axis, input, x, frametime );
  576. }
  577. if( negative )
  578. {
  579. x *= -1;
  580. }
  581. return x;
  582. }
  583. ConVar joy_accel_filter("joy_accel_filter", "0.2");// If the non-accelerated axis is pushed farther than this, then accelerate it, too.
  584. ConVar joy_useNewAcecelMethod("joy_useNewAcecelMethod","1");
  585. ConVar joy_useNewJoystickPegged( "joy_useNewJoystickPeggedTest", "0" );
  586. float CInput::ResponseCurveLookAccelerated( int nSlot, float x, int axis, float otherAxis, float dist, float frametime )
  587. {
  588. envelope_t &envelope = controlEnvelope[ MAX( nSlot, 0 ) ];
  589. float input = x;
  590. float flJoyDist = ( sqrt(x*x + otherAxis * otherAxis) );
  591. bool bIsPegged = ( flJoyDist>= joy_pegged.GetFloat() );
  592. if ( joy_useNewAcecelMethod.GetBool() || joy_useNewJoystickPegged.GetBool() )
  593. {
  594. bIsPegged = IsJoystickPegged( input, otherAxis );
  595. }
  596. float curvParam = joy_gamma.GetFloat() * 2.0f - 1.0f;
  597. // Make X positive to make arithmetic easier for the rest of this function, and
  598. // remember whether we have to flip it back!
  599. bool negative = false;
  600. if( x < 0.0f )
  601. {
  602. negative = true;
  603. x *= -1;
  604. }
  605. // Perform the two-stage mapping.
  606. bool bDoAcceleration = false;// Assume we won't accelerate the input
  607. if( bIsPegged && x > joy_accel_filter.GetFloat() )
  608. {
  609. // Accelerate this axis, since the stick is pegged and
  610. // this axis is pressed farther than the acceleration filter
  611. // Take the lowmap value, or the input, whichever is higher, since
  612. // we don't necesarily know whether this is the axis which is pegged
  613. if( !joy_no_accel_jump.GetBool() )
  614. {
  615. x = MAX( joy_lowmap.GetFloat(), x );
  616. }
  617. bDoAcceleration = true;
  618. }
  619. else
  620. {
  621. // Joystick is languishing in the low-end, turn off acceleration.
  622. envelope.envelopeScale[axis] = 0.0f;
  623. float factor = x / joy_lowend.GetFloat();
  624. if ( joy_useNewAcecelMethod.GetBool() )
  625. {
  626. float divisor = factor * curvParam + 1;
  627. //ReleaseAssert(divisor);
  628. if (divisor != 0.0f)
  629. x = joy_lowmap.GetFloat() * ( factor * ( curvParam + 1 ) / divisor );
  630. }
  631. else
  632. {
  633. x = joy_lowmap.GetFloat() * factor;
  634. }
  635. }
  636. if( bDoAcceleration )
  637. {
  638. float flMax = joy_accelmax.GetFloat();
  639. if( envelope.envelopeScale[axis] < flMax && !joy_useNewAcecelMethod.GetBool() )
  640. {
  641. envelope.envelopeScale[axis] += ( frametime * joy_accelscale.GetFloat() );
  642. if( envelope.envelopeScale[axis] > flMax )
  643. {
  644. envelope.envelopeScale[axis] = flMax;
  645. }
  646. }
  647. float delta = x - joy_lowmap.GetFloat();
  648. x = joy_lowmap.GetFloat() + (delta * envelope.envelopeScale[axis]);
  649. if ( joy_useNewAcecelMethod.GetBool() )
  650. {
  651. float factor = x / joy_lowend.GetFloat();
  652. float divisor = factor * curvParam + 1;
  653. //ReleaseAssert(divisor);
  654. float minx = 0.0f;
  655. if (divisor != 0.0f)
  656. minx = joy_lowmap.GetFloat() * ( factor * ( curvParam + 1 ) / divisor );
  657. x = MAX( x, minx );
  658. }
  659. }
  660. x *= AutoAimDampening( input, axis, dist );
  661. if( axis == YAW && input != 0.0f && joy_display_input.GetBool() )
  662. {
  663. Msg("In:%f Out:%f Frametime:%f\n", input, x, frametime );
  664. }
  665. if( negative )
  666. {
  667. x *= -1;
  668. }
  669. return x;
  670. }
  671. //-----------------------------------------------
  672. //-----------------------------------------------
  673. float CInput::ResponseCurveLookPolynomial( int nSlot, float x, int axis, float otherAxis, float dist, float frametime )
  674. {
  675. // Make X positive to make things easier, just remember whether we have to flip it back!
  676. bool negative = false;
  677. if( x < 0.0f )
  678. {
  679. negative = true;
  680. x *= -1;
  681. }
  682. if ( otherAxis < 0.0f )
  683. {
  684. otherAxis *= -1;
  685. }
  686. envelope_t &envelope = controlEnvelope[ MAX( nSlot, 0 ) ];
  687. float input = x;
  688. float scale = MIN( 1.0f, sqrt(x*x+otherAxis*otherAxis) );
  689. bool bPegged = ( scale >= joy_pegged.GetFloat() ) || IsJoystickPegged( x, otherAxis );
  690. if( axis == YAW && joy_virtual_peg.GetBool() )
  691. {
  692. if( x >= 0.95f )
  693. {
  694. // User has pegged the stick
  695. envelope.peggedAxis[axis] = true;
  696. envelope.axisPeggedDir[axis] = negative;
  697. }
  698. if( envelope.peggedAxis[axis] == true )
  699. {
  700. // User doesn't have the stick pegged on this axis, but they used to.
  701. // If the stick is physically pegged, pretend this axis is still pegged.
  702. if( bPegged && negative == envelope.axisPeggedDir[axis] )
  703. {
  704. // If the user still has the stick physically pegged and hasn't changed direction on
  705. // this axis, keep pretending they have the stick pegged on this axis.
  706. x = 1.0f;
  707. }
  708. else
  709. {
  710. envelope.peggedAxis[axis] = false;
  711. }
  712. }
  713. }
  714. //if ( bPegged )
  715. //{
  716. // x = 1.0f;
  717. //}
  718. float flMaxOutput = 1;
  719. //float flMaxAccel = joy_accelmax.GetFloat();
  720. if( envelope.envelopeScale[axis] < 1.0f )
  721. {
  722. envelope.envelopeScale[axis] += ( frametime * joy_accelscale.GetFloat() );
  723. if( envelope.envelopeScale[axis] > 1.0f )
  724. {
  725. envelope.envelopeScale[axis] = 1.0f;
  726. }
  727. }
  728. //x = joy_curvepoint_3.GetFloat() + (delta * envelope.envelopeScale[axis]);
  729. if ( x > 0 && scale > 0 )
  730. {
  731. x = (joy_curvepoint_end.GetFloat()*sqrt(x*x*x*x*x*x) + joy_curvepoint_4.GetFloat()*sqrt(x*x*x*x*x) + joy_curvepoint_3.GetFloat()*sqrt(x*x*x*x) + joy_curvepoint_2.GetFloat()*sqrt(x*x*x) + joy_curvepoint_1.GetFloat()*sqrt(x*x) + 0.00001f*sqrt(x)) * joy_accelscalepoly.GetFloat();
  732. flMaxOutput = (joy_curvepoint_end.GetFloat() + joy_curvepoint_4.GetFloat() + joy_curvepoint_3.GetFloat() + joy_curvepoint_2.GetFloat() + joy_curvepoint_1.GetFloat() + 0.00001f) * joy_accelscalepoly.GetFloat();
  733. if( x > 0.0f && joy_display_input.GetBool() )
  734. {
  735. //Msg("scale = %f........\n", scale );
  736. Msg("AXIS == %d : 1b: x = :%f, scale = %f\n", axis, x, scale );
  737. }
  738. x *= 1+((otherAxis+scale)*0.75);
  739. }
  740. else
  741. {
  742. envelope.envelopeScale[axis] = 0.0f;
  743. }
  744. // account for pushing diagonally
  745. float flDiagonal = 0;
  746. /*
  747. if ( x > otherAxis )
  748. flDiagonal = (scale-otherAxis) * (otherAxis/x);
  749. else if ( otherAxis > x )
  750. flDiagonal = (scale-x) * (x/otherAxis);
  751. x = MIN( flMaxOutput, x + (flDiagonal*scale) );
  752. */
  753. //if ( bPegged )
  754. // x = flMaxOutput;
  755. x *= envelope.envelopeScale[axis];
  756. x = MIN( flMaxOutput, x );
  757. if( x > 0.0f && joy_display_input.GetBool() )
  758. Msg("flDiagonal == %f : otherAxis = :%f : x = :%f, flMaxOutput = %f\n", flDiagonal, otherAxis, x, flMaxOutput );
  759. x *= AutoAimDampening( input, axis, dist );
  760. if( x > 0.0f && joy_display_input.GetBool() )
  761. {
  762. Msg("AXIS == %d : flJoyDist:%f In:%f Out:%f Frametime:%f\n", axis, scale, input, x, frametime );
  763. }
  764. if( negative )
  765. {
  766. x *= -1;
  767. }
  768. return x;
  769. }
  770. //-----------------------------------------------
  771. //-----------------------------------------------
  772. float CInput::ResponseCurveLook( int nSlot, int curve, float x, int axis, float otherAxis, float dist, float frametime )
  773. {
  774. switch( curve )
  775. {
  776. case 1://Promotion of acceleration
  777. return ResponseCurveLookAccelerated( nSlot, x, axis, otherAxis, dist, frametime );
  778. break;
  779. case 2://Modern
  780. return ResponseCurveLookPolynomial( nSlot, x, axis, otherAxis, dist, frametime );
  781. break;
  782. default:
  783. return ResponseCurveLookDefault( nSlot, x, axis, otherAxis, dist, frametime );
  784. break;
  785. }
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Purpose: Advanced joystick setup
  789. //-----------------------------------------------------------------------------
  790. void CInput::Joystick_Advanced( bool bSilent )
  791. {
  792. m_fJoystickAdvancedInit = true;
  793. // called whenever an update is needed
  794. int i;
  795. DWORD dwTemp;
  796. if ( IsGameConsole() )
  797. {
  798. // Xbox always uses a joystick
  799. in_joystick.SetValue( 1 );
  800. }
  801. for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
  802. {
  803. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  804. PerUserInput_t &user = GetPerUser();
  805. // Initialize all the maps
  806. for ( i = 0; i < MAX_JOYSTICK_AXES; i++ )
  807. {
  808. user.m_rgAxes[i].AxisMap = GAME_AXIS_NONE;
  809. user.m_rgAxes[i].ControlMap = JOY_ABSOLUTE_AXIS;
  810. }
  811. if ( !joy_advanced.GetBool() )
  812. {
  813. // default joystick initialization
  814. // 2 axes only with joystick control
  815. user.m_rgAxes[JOY_AXIS_X].AxisMap = GAME_AXIS_YAW;
  816. user.m_rgAxes[JOY_AXIS_Y].AxisMap = GAME_AXIS_FORWARD;
  817. }
  818. else
  819. {
  820. if ( !bSilent &&
  821. hh == 0 && Q_stricmp( joy_name.GetString(), "joystick") )
  822. {
  823. // notify user of advanced controller
  824. Msg( "Using joystick '%s' configuration\n", joy_name.GetString() );
  825. }
  826. static SplitScreenConVarRef s_joy_movement_stick( "joy_movement_stick" );
  827. bool bJoyMovementStick = s_joy_movement_stick.GetBool( hh );
  828. // advanced initialization here
  829. // data supplied by user via joy_axisn cvars
  830. dwTemp = ( bJoyMovementStick ) ? (DWORD)joy_advaxisu.GetInt() : (DWORD)joy_advaxisx.GetInt();
  831. user.m_rgAxes[JOY_AXIS_X].AxisMap = dwTemp & 0x0000000f;
  832. user.m_rgAxes[JOY_AXIS_X].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  833. dwTemp = ( bJoyMovementStick ) ? (DWORD)joy_advaxisr.GetInt() : (DWORD)joy_advaxisy.GetInt();
  834. user.m_rgAxes[JOY_AXIS_Y].AxisMap = dwTemp & 0x0000000f;
  835. user.m_rgAxes[JOY_AXIS_Y].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  836. dwTemp = (DWORD)joy_advaxisz.GetInt();
  837. user.m_rgAxes[JOY_AXIS_Z].AxisMap = dwTemp & 0x0000000f;
  838. user.m_rgAxes[JOY_AXIS_Z].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  839. dwTemp = ( bJoyMovementStick ) ? (DWORD)joy_advaxisy.GetInt() : (DWORD)joy_advaxisr.GetInt();
  840. user.m_rgAxes[JOY_AXIS_R].AxisMap = dwTemp & 0x0000000f;
  841. user.m_rgAxes[JOY_AXIS_R].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  842. dwTemp = ( bJoyMovementStick ) ? (DWORD)joy_advaxisx.GetInt() : (DWORD)joy_advaxisu.GetInt();
  843. user.m_rgAxes[JOY_AXIS_U].AxisMap = dwTemp & 0x0000000f;
  844. user.m_rgAxes[JOY_AXIS_U].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  845. dwTemp = (DWORD)joy_advaxisv.GetInt();
  846. user.m_rgAxes[JOY_AXIS_V].AxisMap = dwTemp & 0x0000000f;
  847. user.m_rgAxes[JOY_AXIS_V].ControlMap = dwTemp & JOY_RELATIVE_AXIS;
  848. if ( !bSilent )
  849. {
  850. Msg( "Advanced joystick settings initialized for joystick %d\n------------\n", hh + 1 );
  851. DescribeJoystickAxis( hh, "x axis", &user.m_rgAxes[JOY_AXIS_X] );
  852. DescribeJoystickAxis( hh, "y axis", &user.m_rgAxes[JOY_AXIS_Y] );
  853. DescribeJoystickAxis( hh, "z axis", &user.m_rgAxes[JOY_AXIS_Z] );
  854. DescribeJoystickAxis( hh, "r axis", &user.m_rgAxes[JOY_AXIS_R] );
  855. DescribeJoystickAxis( hh, "u axis", &user.m_rgAxes[JOY_AXIS_U] );
  856. DescribeJoystickAxis( hh, "v axis", &user.m_rgAxes[JOY_AXIS_V] );
  857. }
  858. }
  859. }
  860. #if defined( SWARM_DLL ) || defined( PORTAL )
  861. // Load the xbox controller cfg file if it hasn't been loaded.
  862. if ( in_joystick.GetBool() )
  863. {
  864. if ( joy_xcontroller_cfg_loaded.GetBool() == false )
  865. {
  866. engine->ClientCmd( "exec joy_configuration" PLATFORM_EXT ".cfg" );
  867. joy_xcontroller_cfg_loaded.SetValue( 1 );
  868. }
  869. }
  870. else if ( joy_xcontroller_cfg_loaded.GetBool() )
  871. {
  872. engine->ClientCmd( "exec undo360controller.cfg" );
  873. joy_xcontroller_cfg_loaded.SetValue( 0 );
  874. }
  875. #else // !SWARM_DLL && !PORTAL
  876. #if !defined( _PS3 )
  877. // [Forrest] For CStrike 1.5 we want to load 360controller.cfg on Xbox as well as PC.
  878. // If we have an xcontroller on the PC, load the cfg file if it hasn't been loaded.
  879. // [Forrest] engine->ClientCmd didn't go through (FCVAR_CLIENTCMD_CAN_EXECUTE prevented running command).
  880. // Changed it to engine->ClientCmd_Unrestricted.
  881. ConVarRef var( "joy_xcontroller_found" );
  882. if ( var.IsValid() && var.GetBool() && in_joystick.GetBool() )
  883. {
  884. if ( joy_xcontroller_cfg_loaded.GetBool() == false )
  885. {
  886. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  887. {
  888. engine->ClientCmd_Unrestricted( "exec controller" PLATFORM_EXT ".cfg", false, i, false );
  889. }
  890. joy_xcontroller_cfg_loaded.SetValue( 1 );
  891. }
  892. }
  893. else if ( joy_xcontroller_cfg_loaded.GetBool() )
  894. {
  895. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  896. {
  897. engine->ClientCmd_Unrestricted( "exec undo360controller.cfg", false, i, false );
  898. }
  899. joy_xcontroller_cfg_loaded.SetValue( 0 );
  900. }
  901. #endif
  902. #endif // SWARM_DLL
  903. }
  904. //-----------------------------------------------------------------------------
  905. // Purpose:
  906. // Input : index -
  907. // Output : char const
  908. //-----------------------------------------------------------------------------
  909. char const *CInput::DescribeAxis( int index )
  910. {
  911. // $FIXME(hpe) the string command syntax differs from xbla; need to verify
  912. switch ( index )
  913. {
  914. case GAME_AXIS_FORWARD:
  915. return "forward";
  916. case GAME_AXIS_PITCH:
  917. return "pitch";
  918. case GAME_AXIS_SIDE:
  919. return "strafe";
  920. case GAME_AXIS_YAW:
  921. return "yaw";
  922. case GAME_AXIS_NONE:
  923. default:
  924. return "n/a";
  925. }
  926. return "n/a";
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Purpose:
  930. // Input : *axis -
  931. // *mapping -
  932. //-----------------------------------------------------------------------------
  933. void CInput::DescribeJoystickAxis( int nJoystick, char const *axis, joy_axis_t *mapping )
  934. {
  935. if ( !mapping->AxisMap )
  936. {
  937. Msg( "joy%d %s: unmapped\n", nJoystick + 1, axis );
  938. }
  939. else
  940. {
  941. Msg( "joy%d %s: %s (%s)\n",
  942. nJoystick + 1,
  943. axis,
  944. DescribeAxis( mapping->AxisMap ),
  945. mapping->ControlMap != 0 ? "relative" : "absolute" );
  946. }
  947. }
  948. //-----------------------------------------------------------------------------
  949. // Purpose: Allow joystick to issue key events
  950. // Not currently used - controller button events are pumped through the windprocs. KWD
  951. //-----------------------------------------------------------------------------
  952. void CInput::ControllerCommands( void )
  953. {
  954. }
  955. //-----------------------------------------------------------------------------
  956. // Purpose: Scales the raw analog value to lie withing the axis range (full range - deadzone )
  957. //-----------------------------------------------------------------------------
  958. float CInput::ScaleAxisValue( const float axisValue, const float axisThreshold )
  959. {
  960. // Xbox scales the range of all axes in the inputsystem. PC can't do that because each axis mapping
  961. // has a (potentially) unique threshold value. If all axes were restricted to a single threshold
  962. // as they are on the Xbox, this function could move to inputsystem and be slightly more optimal.
  963. float result = 0.f;
  964. if ( IsPC() )
  965. {
  966. if ( axisValue < -axisThreshold )
  967. {
  968. result = ( axisValue + axisThreshold ) / ( MAX_BUTTONSAMPLE - axisThreshold );
  969. }
  970. else if ( axisValue > axisThreshold )
  971. {
  972. result = ( axisValue - axisThreshold ) / ( MAX_BUTTONSAMPLE - axisThreshold );
  973. }
  974. }
  975. else
  976. {
  977. result = axisValue * ( 1.f / MAX_BUTTONSAMPLE );
  978. }
  979. return result;
  980. }
  981. void CInput::Joystick_SetSampleTime(float frametime)
  982. {
  983. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  984. {
  985. m_PerUser[ i ].m_flRemainingJoystickSampleTime = frametime;
  986. }
  987. }
  988. float CInput::Joystick_GetPitch( void )
  989. {
  990. if ( !ControllerModeActive() )
  991. return 0.0f;
  992. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  993. PerUserInput_t &user = GetPerUser( nSlot );
  994. return user.m_flPreviousJoystickPitch;
  995. }
  996. float CInput::Joystick_GetYaw( void )
  997. {
  998. if ( !ControllerModeActive() )
  999. return 0.0f;
  1000. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1001. PerUserInput_t &user = GetPerUser( nSlot );
  1002. return user.m_flPreviousJoystickYaw;
  1003. }
  1004. void CInput::Joystick_Querry( float &forward, float &side, float &pitch, float &yaw )
  1005. {
  1006. bool bAbsoluteYaw, bAbsolutePitch;
  1007. JoyStickSampleAxes( forward, side, pitch, yaw, bAbsoluteYaw, bAbsolutePitch );
  1008. }
  1009. void CInput::Joystick_ForceRecentering( int nStick, bool bSet /*= true*/ )
  1010. {
  1011. if ( nStick < 0 || nStick > 1 )
  1012. return;
  1013. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1014. PerUserInput_t &user = GetPerUser( nSlot );
  1015. user.m_bForceJoystickRecentering[ nStick ] = bSet;
  1016. }
  1017. extern void IN_ForceSpeedUp( );
  1018. extern void IN_ForceSpeedDown( );
  1019. bool CInput::ControllerModeActive( void )
  1020. {
  1021. return ( in_joystick.GetInt() != 0 && m_bControllerMode );
  1022. }
  1023. //--------------------------------------------------------------------
  1024. // See if we want to use the joystick
  1025. //--------------------------------------------------------------------
  1026. bool CInput::JoyStickActive()
  1027. {
  1028. // verify joystick is available and that the user wants to use it
  1029. if ( !in_joystick.GetInt() || 0 == inputsystem->GetJoystickCount() )
  1030. return false;
  1031. // Skip out if vgui or gameui is active
  1032. if ( !g_pInputStackSystem->IsTopmostEnabledContext( m_hInputContext ) )
  1033. return false;
  1034. return true;
  1035. }
  1036. //--------------------------------------------------------------------
  1037. // Reads joystick values
  1038. //--------------------------------------------------------------------
  1039. void CInput::JoyStickSampleAxes( float &forward, float &side, float &pitch, float &yaw, bool &bAbsoluteYaw, bool &bAbsolutePitch )
  1040. {
  1041. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1042. PerUserInput_t &user = GetPerUser( nSlot );
  1043. struct axis_t
  1044. {
  1045. float value;
  1046. int controlType;
  1047. };
  1048. axis_t gameAxes[ MAX_GAME_AXES ];
  1049. memset( &gameAxes, 0, sizeof(gameAxes) );
  1050. // Get each joystick axis value, and normalize the range
  1051. for ( int i = 0; i < MAX_JOYSTICK_AXES; ++i )
  1052. {
  1053. if ( GAME_AXIS_NONE == user.m_rgAxes[i].AxisMap )
  1054. continue;
  1055. float fAxisValue = inputsystem->GetAnalogValue( (AnalogCode_t)JOYSTICK_AXIS( GET_ACTIVE_SPLITSCREEN_SLOT(), i ) );
  1056. if ( joy_wwhack2.GetInt() != 0 )
  1057. {
  1058. // this is a special formula for the Logitech WingMan Warrior
  1059. // y=ax^b; where a = 300 and b = 1.3
  1060. // also x values are in increments of 800 (so this is factored out)
  1061. // then bounds check result to level out excessively high spin rates
  1062. float fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
  1063. if (fTemp > 14000.0)
  1064. fTemp = 14000.0;
  1065. // restore direction information
  1066. fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
  1067. }
  1068. unsigned int idx = user.m_rgAxes[i].AxisMap;
  1069. gameAxes[idx].value = fAxisValue;
  1070. gameAxes[idx].controlType = user.m_rgAxes[i].ControlMap;
  1071. }
  1072. // Before these axes are allowed to return values must bring them back to mostly centered
  1073. if ( user.m_bForceJoystickRecentering[ 0 ] )
  1074. {
  1075. if ( fabsf( gameAxes[GAME_AXIS_FORWARD].value ) < 0.1f && fabsf( gameAxes[GAME_AXIS_SIDE].value ) < 0.1f )
  1076. {
  1077. user.m_bForceJoystickRecentering[ 0 ] = false;
  1078. }
  1079. gameAxes[GAME_AXIS_FORWARD].value = 0.0f;
  1080. gameAxes[GAME_AXIS_SIDE].value = 0.0f;
  1081. }
  1082. // Before these axes are allowed to return values must bring them back to mostly centered
  1083. if ( user.m_bForceJoystickRecentering[ 1 ] )
  1084. {
  1085. if ( fabsf( gameAxes[GAME_AXIS_PITCH].value ) < 0.1f && fabsf( gameAxes[GAME_AXIS_YAW].value ) < 0.1f )
  1086. {
  1087. user.m_bForceJoystickRecentering[ 1 ] = false;
  1088. }
  1089. gameAxes[GAME_AXIS_PITCH].value = 0.0f;
  1090. gameAxes[GAME_AXIS_YAW].value = 0.0f;
  1091. }
  1092. // Re-map the axis values if necessary, based on the joystick configuration
  1093. if ( (joy_advanced.GetInt() == 0) && (in_jlook.GetPerUser( nSlot ).state & 1) )
  1094. {
  1095. // user wants forward control to become pitch control
  1096. gameAxes[GAME_AXIS_PITCH] = gameAxes[GAME_AXIS_FORWARD];
  1097. gameAxes[GAME_AXIS_FORWARD].value = 0;
  1098. // if mouse invert is on, invert the joystick pitch value
  1099. // Note: only absolute control support here - joy_advanced = 0
  1100. if ( m_pitch->GetFloat() < 0.0 )
  1101. {
  1102. gameAxes[GAME_AXIS_PITCH].value *= -1;
  1103. }
  1104. }
  1105. if ( (in_strafe.GetPerUser( nSlot ).state & 1) || lookstrafe.GetFloat() && (in_jlook.GetPerUser( nSlot ).state & 1) )
  1106. {
  1107. // user wants yaw control to become side control
  1108. gameAxes[GAME_AXIS_SIDE] = gameAxes[GAME_AXIS_YAW];
  1109. gameAxes[GAME_AXIS_YAW].value = 0;
  1110. }
  1111. static SplitScreenConVarRef joy_movement_stick("joy_movement_stick");
  1112. if( joy_movement_stick.IsValid() && joy_movement_stick.GetInt( nSlot ) == 2 )
  1113. {
  1114. axis_t swap = gameAxes[GAME_AXIS_YAW];
  1115. gameAxes[GAME_AXIS_YAW] = gameAxes[GAME_AXIS_SIDE];
  1116. gameAxes[GAME_AXIS_SIDE] = swap;
  1117. }
  1118. forward = ScaleAxisValue( gameAxes[GAME_AXIS_FORWARD].value, MAX_BUTTONSAMPLE * joy_forwardthreshold.GetFloat() );
  1119. side = ScaleAxisValue( gameAxes[GAME_AXIS_SIDE].value, MAX_BUTTONSAMPLE * joy_sidethreshold.GetFloat() );
  1120. pitch = ScaleAxisValue( gameAxes[GAME_AXIS_PITCH].value, MAX_BUTTONSAMPLE * joy_pitchthreshold.GetFloat() );
  1121. yaw = ScaleAxisValue( gameAxes[GAME_AXIS_YAW].value, MAX_BUTTONSAMPLE * joy_yawthreshold.GetFloat() );
  1122. bAbsoluteYaw = ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_YAW].controlType );
  1123. bAbsolutePitch = ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_PITCH].controlType );
  1124. // If we're inverting our joystick, do so
  1125. static SplitScreenConVarRef s_joy_inverty( "joy_inverty" );
  1126. bool isInverted = s_joy_inverty.IsValid() && s_joy_inverty.GetBool( nSlot );
  1127. if ( !isInverted )
  1128. {
  1129. pitch *= -1.0f;
  1130. }
  1131. }
  1132. //--------------------------------------------------------------------
  1133. // drive yaw, pitch and move like a screen relative platformer game
  1134. //--------------------------------------------------------------------
  1135. void CInput::JoyStickThirdPersonPlatformer( CUserCmd *cmd, float &forward, float &side, float &pitch, float &yaw )
  1136. {
  1137. // Get starting angles
  1138. QAngle viewangles;
  1139. engine->GetViewAngles( viewangles );
  1140. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1141. PerUserInput_t &user = GetPerUser( nSlot );
  1142. if ( forward || side )
  1143. {
  1144. // apply turn control [ YAW ]
  1145. // factor in the camera offset, so that the move direction is relative to the thirdperson camera
  1146. viewangles[ YAW ] = RAD2DEG(atan2(-side, -forward)) + user.m_vecCameraOffset[ YAW ];
  1147. engine->SetViewAngles( viewangles );
  1148. // apply movement
  1149. Vector2D moveDir( forward, side );
  1150. cmd->forwardmove += moveDir.Length() * cl_forwardspeed.GetFloat();
  1151. }
  1152. if ( pitch || yaw )
  1153. {
  1154. static SplitScreenConVarRef s_joy_yawsensitivity( "joy_yawsensitivity" );
  1155. static SplitScreenConVarRef s_joy_pitchsensitivity( "joy_pitchsensitivity" );
  1156. // look around with the camera
  1157. user.m_vecCameraOffset[ PITCH ] += pitch * s_joy_pitchsensitivity.GetFloat( nSlot );
  1158. user.m_vecCameraOffset[ YAW ] += yaw * s_joy_yawsensitivity.GetFloat( nSlot );
  1159. }
  1160. if ( forward || side || pitch || yaw )
  1161. {
  1162. // update the ideal pitch and yaw
  1163. cam_idealpitch.SetValue( user.m_vecCameraOffset[ PITCH ] - viewangles[ PITCH ] );
  1164. cam_idealyaw.SetValue( user.m_vecCameraOffset[ YAW ] - viewangles[ YAW ] );
  1165. }
  1166. }
  1167. //-----------------------------------------------
  1168. // Turns viewangles based on sampled joystick
  1169. //-----------------------------------------------
  1170. void CInput::JoyStickTurn( CUserCmd *cmd, float &yaw, float &pitch, float frametime, bool bAbsoluteYaw, bool bAbsolutePitch )
  1171. {
  1172. // Get starting angles
  1173. QAngle viewangles;
  1174. engine->GetViewAngles( viewangles );
  1175. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1176. // PerUserInput_t &user = GetPerUser( nSlot );
  1177. static SplitScreenConVarRef s_joy_yawsensitivity( "joy_yawsensitivity" );
  1178. static SplitScreenConVarRef s_joy_pitchsensitivity( "joy_pitchsensitivity" );
  1179. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1180. bool bSpecThird = pLocalPlayer && pLocalPlayer->GetObserverMode() == OBS_MODE_CHASE;
  1181. Vector2D move( yaw, pitch );
  1182. float dist = move.Length();
  1183. bool bVariableFrametime = joy_variable_frametime.GetBool();
  1184. float lookFrametime = bVariableFrametime ? frametime : gpGlobals->frametime;
  1185. float aspeed = lookFrametime * GetHud().GetFOVSensitivityAdjust();
  1186. if ( bSpecThird )
  1187. aspeed *= 1.5;
  1188. // No quick turn so just sample the joystick
  1189. float angle = 0.0f;
  1190. // Sample the joystick.
  1191. if ( bVariableFrametime || frametime != gpGlobals->frametime )
  1192. {
  1193. if ( bAbsoluteYaw )
  1194. {
  1195. float fAxisValue = ResponseCurveLook( nSlot, joy_response_look.GetInt(), yaw, YAW, pitch, dist, lookFrametime );
  1196. angle = fAxisValue * s_joy_yawsensitivity.GetFloat( nSlot ) * aspeed * cl_yawspeed.GetFloat();
  1197. }
  1198. else
  1199. {
  1200. angle = yaw * s_joy_yawsensitivity.GetFloat( nSlot ) * aspeed * 180.0;
  1201. }
  1202. }
  1203. // Update and apply turn control. This may produce a new angle if we're doing a quick turn.
  1204. angle = UpdateAndGetQuickTurnYaw( nSlot, lookFrametime, angle );
  1205. viewangles[YAW] += angle;
  1206. cmd->mousedx = angle;
  1207. // apply look control
  1208. if ( in_jlook.GetPerUser( nSlot ).state & 1 )
  1209. {
  1210. float angle = 0;
  1211. if ( bVariableFrametime || frametime != gpGlobals->frametime )
  1212. {
  1213. if ( bAbsolutePitch )
  1214. {
  1215. float fAxisValue = ResponseCurveLook( nSlot, joy_response_look_pitch.GetInt(), pitch, PITCH, yaw, dist, lookFrametime );
  1216. angle = fAxisValue * s_joy_pitchsensitivity.GetFloat( nSlot ) * aspeed * cl_pitchspeed.GetFloat();
  1217. }
  1218. else
  1219. {
  1220. angle = pitch * s_joy_pitchsensitivity.GetFloat( nSlot ) * aspeed * 180.0;
  1221. }
  1222. }
  1223. viewangles[PITCH] += angle;
  1224. cmd->mousedy = angle;
  1225. view->StopPitchDrift();
  1226. if ( pitch == 0.f && lookspring.GetFloat() == 0.f )
  1227. {
  1228. // no pitch movement
  1229. // disable pitch return-to-center unless requested by user
  1230. // *** this code can be removed when the lookspring bug is fixed
  1231. // *** the bug always has the lookspring feature on
  1232. view->StopPitchDrift();
  1233. }
  1234. }
  1235. viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() );
  1236. engine->SetViewAngles( viewangles );
  1237. }
  1238. //---------------------------------------------------------------------
  1239. // Calculates strafe and forward/back motion based on sampled joystick
  1240. //---------------------------------------------------------------------
  1241. void CInput::JoyStickForwardSideControl( float forward, float side, float &joyForwardMove, float &joySideMove )
  1242. {
  1243. joyForwardMove = joySideMove = 0.0f;
  1244. // apply forward and side control
  1245. if ( joy_response_move.GetInt() > 6 && joy_circle_correct.GetBool() )
  1246. {
  1247. // ok the 360 controller is scaled to a circular area. our movement is scaled to the square two axis,
  1248. // so diagonal needs to be scaled properly to full speed.
  1249. bool bInWalk = true;
  1250. float scale = MIN(1.0f,sqrt(forward*forward+side*side));
  1251. if ( scale > 0.01f )
  1252. {
  1253. float val;
  1254. if ( scale > joy_sensitive_step2.GetFloat() )
  1255. {
  1256. bInWalk = false;
  1257. }
  1258. float scaledVal = ResponseCurve( joy_response_move.GetInt(), scale, PITCH, fabsf( joy_forwardsensitivity.GetFloat() ) );
  1259. val = scaledVal * ( ( forward * Sign( joy_forwardsensitivity.GetFloat() ) ) / scale );
  1260. joyForwardMove += val * cl_forwardspeed.GetFloat();
  1261. scaledVal = ResponseCurve( joy_response_move.GetInt(), scale, PITCH, fabsf( joy_sidesensitivity.GetFloat() ) );
  1262. val = scaledVal * ( ( side * Sign( joy_sidesensitivity.GetFloat() ) ) / scale );
  1263. joySideMove += val * cl_sidespeed.GetFloat();
  1264. // big hack here, if we are not moving past the joy_sensitive_step2 thresh hold then walk.
  1265. if ( bInWalk )
  1266. {
  1267. IN_ForceSpeedDown();
  1268. }
  1269. else
  1270. {
  1271. IN_ForceSpeedUp();
  1272. }
  1273. }
  1274. else
  1275. {
  1276. IN_ForceSpeedUp();
  1277. }
  1278. }
  1279. else
  1280. {
  1281. // apply forward and side control
  1282. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1283. int iResponseCurve = 0;
  1284. if ( pLocalPlayer && pLocalPlayer->IsInAVehicle() )
  1285. {
  1286. iResponseCurve = pLocalPlayer->GetVehicle() ? pLocalPlayer->GetVehicle()->GetJoystickResponseCurve() : joy_response_move_vehicle.GetInt();
  1287. }
  1288. else
  1289. {
  1290. iResponseCurve = joy_response_move.GetInt();
  1291. }
  1292. float val = ResponseCurve( iResponseCurve, forward, PITCH, joy_forwardsensitivity.GetFloat() );
  1293. joyForwardMove += val * cl_forwardspeed.GetFloat();
  1294. val = ResponseCurve( iResponseCurve, side, YAW, joy_sidesensitivity.GetFloat() );
  1295. joySideMove += val * cl_sidespeed.GetFloat();
  1296. }
  1297. }
  1298. // expects a -1.0 - 1.0 value
  1299. // returns a 0.0 - 1.2 value, signed to match the input
  1300. float CInput::HandleMotionControllerInputSmoothing( float flDeadZonePct, float val )
  1301. {
  1302. bool isPositive = val > 0.0f;
  1303. float absVal = abs(val);
  1304. if ( absVal <= flDeadZonePct )
  1305. return 0.0f;
  1306. // Allow player to point off the screen if they've made the dead zone the size of the screen.
  1307. float flBandSize = mc_accel_band_size.GetFloat();
  1308. float normalizedAfterDeadzone = (absVal - flDeadZonePct) / flBandSize;
  1309. float result = 0.0f;
  1310. if ( normalizedAfterDeadzone > mc_turnPctPegged.GetFloat() )
  1311. {
  1312. // in our high acceleration zone, bump up the value
  1313. result = mc_turnPctPeggedMultiplier.GetFloat();
  1314. }
  1315. else
  1316. {
  1317. // low acceleration
  1318. // X*X method
  1319. switch (mc_turn_curve.GetInt() )
  1320. {
  1321. case 0:
  1322. result = normalizedAfterDeadzone;
  1323. break;
  1324. case 1:
  1325. result = normalizedAfterDeadzone * normalizedAfterDeadzone;
  1326. break;
  1327. case 2:
  1328. result = normalizedAfterDeadzone * normalizedAfterDeadzone * normalizedAfterDeadzone;
  1329. break;
  1330. }
  1331. }
  1332. result = isPositive ? result : result * -1.0f;
  1333. return result;
  1334. }
  1335. //-----------------------------------------------------------------------------
  1336. // Purpose: Apply motion controller to CUserCmd creation
  1337. // Input : frametime -
  1338. // *cmd -
  1339. //-----------------------------------------------------------------------------
  1340. void CInput::MotionControllerMove( float frametime, CUserCmd *cmd )
  1341. {
  1342. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1343. C_CSPlayer* pPlayer = C_CSPlayer::GetLocalCSPlayer();
  1344. Assert( pPlayer );
  1345. // [dkorus] make sure our max turn rate is based on our zoom level sensitivity
  1346. float flDeadZonePct = mc_dead_zone_radius.GetFloat();
  1347. float flScreenClamp = mc_screen_clamp.GetFloat();
  1348. int width=0, height=0;
  1349. materials->GetBackBufferDimensions( width, height );
  1350. float fX = inputsystem->GetMotionControllerPosX();
  1351. float fY = inputsystem->GetMotionControllerPosY();
  1352. static float s_lastCursorValueX = fX;
  1353. static float s_lastCursorValueY = fY;
  1354. static QAngle s_referenceDirection;
  1355. static float s_FOVSensitivityAdjust = 1.0f;
  1356. static float s_FOVOffsetX = 0.0f;
  1357. static float s_FOVOffsetY = 0.0f;
  1358. static float s_TargetFOVOffsetX = 0.0f;
  1359. static float s_TargetFOVOffsetY = 0.0f;
  1360. // Don't consider pointer input unless we're actively in the game. Otherwise our view will change outside of when we want it to.
  1361. int iObserverMode = pPlayer->GetObserverMode();
  1362. bool ignorePointerInput = ( iObserverMode == OBS_MODE_DEATHCAM || iObserverMode == OBS_MODE_FREEZECAM );
  1363. #if defined( INCLUDE_SCALEFORM )
  1364. // If we're in the pause menu, then lock the cursor to the screen.
  1365. if ( g_pScaleformUI->SlotDeniesInputToGame( SF_SS_SLOT( nSlot ) ) )
  1366. {
  1367. ignorePointerInput = true;
  1368. }
  1369. #endif
  1370. // If we're in the pause menu, then lock the cursor to the screen.
  1371. if ( ignorePointerInput )
  1372. {
  1373. // Move this to center screen.
  1374. fX = s_lastCursorValueX * 0.85f;
  1375. fY = s_lastCursorValueY * 0.85f;
  1376. }
  1377. bool bLookingAtTarget = pPlayer->IsCursorOnAutoAimTarget();
  1378. // Free moving cursor dampening code.
  1379. static float s_fDampeningValue = 0.0f; // s_fDampeningValue: 0.0 don't dampen, 1.0 fully locked in place.
  1380. float fTargetDampening = 0.0f;
  1381. if ( bLookingAtTarget )
  1382. {
  1383. fTargetDampening = mc_max_dampening.GetFloat();
  1384. }
  1385. // This little bit of code gives us a frame rate independent blend value.
  1386. float blend_t = 1.0f - pow( mc_dampening_blend_amount.GetFloat(), frametime );
  1387. s_fDampeningValue += ( fTargetDampening - s_fDampeningValue )*blend_t;
  1388. // Turn Dampening code.
  1389. static float s_fTurnDampeningValue = 0.0f;
  1390. float fTargetTurnDampening = 0.0f;
  1391. if ( bLookingAtTarget )
  1392. {
  1393. fTargetTurnDampening = mc_max_turn_dampening.GetFloat();
  1394. }
  1395. // This little bit of code gives us a frame rate independent blend value.
  1396. blend_t = 1.0f - pow( mc_turn_dampening_blend_amount.GetFloat(), frametime );
  1397. s_fTurnDampeningValue += ( fTargetTurnDampening - s_fTurnDampeningValue )*blend_t;
  1398. // handle turning the view with the motion controller
  1399. QAngle currentViewAngles;
  1400. engine->GetViewAngles( currentViewAngles );
  1401. if ( mc_zoomed_aim_style.GetInt() == 1 )
  1402. {
  1403. if ( !pPlayer->m_bIsScoped )
  1404. {
  1405. // Only set the reference direction to the current view when we are not zoomed in.
  1406. s_referenceDirection = currentViewAngles;
  1407. }
  1408. }
  1409. else
  1410. {
  1411. s_referenceDirection = currentViewAngles;
  1412. }
  1413. CWeaponCSBase *pWeapon = ( CWeaponCSBase* )pPlayer->GetActiveWeapon();
  1414. float fTurnDampeningMultiplier = 1.0f;
  1415. if ( pWeapon )
  1416. {
  1417. if ( mc_zoomed_aim_style.GetInt() == 1 )
  1418. {
  1419. // For non scoped weapons like the bomb and knife, only do clamping if we're not scoped.
  1420. if ( !pWeapon->WantReticleShown() && !pPlayer->m_bIsScoped )
  1421. {
  1422. flScreenClamp = 0.0f;
  1423. flDeadZonePct = mc_zoomed_out_dead_zone_radius.GetFloat();
  1424. }
  1425. }
  1426. else
  1427. {
  1428. // Lock reticle if we're using a scoped weapon with our motion controller.
  1429. // We do this by setting the screen clamp to zero so that we move like with an analog stick.
  1430. // We also want to lock when we have a sniper rifle because the reticule will not show up.
  1431. if ( !pWeapon->WantReticleShown() ||
  1432. ( mc_always_lock_ret_on_zoom.GetBool() && pPlayer->m_bIsScoped ) )
  1433. {
  1434. flScreenClamp = 0.0f;
  1435. // If in addition to not showing the reticule we are also zoomed in, apply dampening to turning.
  1436. if ( pPlayer->m_bIsScoped )
  1437. {
  1438. // If we're zoomed in, we want to apply the dampening to turning to help lock onto the enemies.
  1439. fTurnDampeningMultiplier = (1.0f - s_fTurnDampeningValue);
  1440. // Zoomed in weapons get a zero dead zone to make aiming smoother.
  1441. flDeadZonePct = 0.0f;
  1442. }
  1443. else
  1444. {
  1445. // We add a bit of deadzone when zoomed out so that world navigation is easier.
  1446. // It also helps to keep your aim on your target after firing if the weapon pops back to zoomed out.
  1447. flDeadZonePct = mc_zoomed_out_dead_zone_radius.GetFloat();
  1448. }
  1449. }
  1450. }
  1451. }
  1452. // We increase the deadzone size for pitch by 1.5
  1453. const float flPitchDeadZoneScale = 1.5f;
  1454. float pitchDeadZone = clamp( flDeadZonePct * flPitchDeadZoneScale, 0.0f, 0.9f );
  1455. // Calculate the pitch and yaw deltas.
  1456. const float flCurrFOVScale = GetHud().GetFOVSensitivityAdjust();
  1457. if ( s_FOVSensitivityAdjust != flCurrFOVScale )
  1458. {
  1459. if ( flCurrFOVScale == 1.0f )
  1460. {
  1461. // Set the offset to put the cursor in the middle of the screen.
  1462. s_FOVOffsetX = -s_lastCursorValueX * flCurrFOVScale;
  1463. s_FOVOffsetY = -s_lastCursorValueY * flCurrFOVScale;
  1464. // Now we want to zero the offset over time.
  1465. s_TargetFOVOffsetX = 0.0f;
  1466. s_TargetFOVOffsetY = 0.0f;
  1467. }
  1468. else
  1469. {
  1470. // We're zooming in on an offset position, so we need to an offset compensation here.
  1471. // save off the offsets from the last cursor value.
  1472. // The last cursor position on the screen was
  1473. float lastAdjustedX = s_lastCursorValueX * s_FOVSensitivityAdjust + s_FOVOffsetX;
  1474. float lastAdjustedY = s_lastCursorValueY * s_FOVSensitivityAdjust + s_FOVOffsetY;
  1475. // With the new FOV scale, the offsets to give us the same position is:
  1476. s_TargetFOVOffsetX = lastAdjustedX - s_lastCursorValueX * flCurrFOVScale;
  1477. s_TargetFOVOffsetY = lastAdjustedY - s_lastCursorValueY * flCurrFOVScale;
  1478. // Set the offset immediately since we don't need or want to blend to this.
  1479. // The blending is for zooming out when the cursor will not be pointing where we were looking.
  1480. s_FOVOffsetX = s_TargetFOVOffsetX;
  1481. s_FOVOffsetY = s_TargetFOVOffsetY;
  1482. }
  1483. s_FOVSensitivityAdjust = flCurrFOVScale;
  1484. }
  1485. blend_t = 1.0f - pow( mc_zoom_out_cursor_offset_blend.GetFloat(), frametime );
  1486. s_FOVOffsetX += ( s_TargetFOVOffsetX - s_FOVOffsetX ) * blend_t;
  1487. s_FOVOffsetY += ( s_TargetFOVOffsetY - s_FOVOffsetY ) * blend_t;
  1488. float flMaxTurnRate = mc_max_yawrate.GetFloat() * s_FOVSensitivityAdjust;
  1489. float flMaxPitchRate = mc_max_pitchrate.GetFloat() * s_FOVSensitivityAdjust;
  1490. float smoothedX = HandleMotionControllerInputSmoothing( flDeadZonePct, fX );
  1491. float smoothedY = HandleMotionControllerInputSmoothing( pitchDeadZone, fY );
  1492. float deltaYaw = -smoothedX * flMaxTurnRate * frametime * fTurnDampeningMultiplier;
  1493. float deltaPitch = -smoothedY * flMaxPitchRate * frametime * fTurnDampeningMultiplier;
  1494. // Update and apply turn control. This may produce a new angle if we're doing a quick turn.
  1495. deltaYaw = UpdateAndGetQuickTurnYaw( nSlot, frametime, deltaYaw );
  1496. s_referenceDirection[YAW] += deltaYaw;
  1497. s_referenceDirection[PITCH] += deltaPitch;
  1498. if ( joy_autoAimDampenMethod.GetInt() == 1 )
  1499. {
  1500. // If we are dampening, we reduce the amount we update towards our target vector.
  1501. fX = s_lastCursorValueX + (fX - s_lastCursorValueX) * (1.0f - s_fDampeningValue);
  1502. fY = s_lastCursorValueY + (fY - s_lastCursorValueY) * (1.0f - s_fDampeningValue);
  1503. }
  1504. fX = clamp( fX, -flScreenClamp, flScreenClamp );
  1505. fY = clamp( fY, -flScreenClamp, flScreenClamp );
  1506. float adjustedX = fX * s_FOVSensitivityAdjust + s_FOVOffsetX;
  1507. float adjustedY = fY * s_FOVSensitivityAdjust + s_FOVOffsetY;
  1508. Vector forward, right, up;
  1509. // Get the orientation matrix for the camera.
  1510. AngleVectors (s_referenceDirection, &forward, &right, &up );
  1511. // Forward project the cursor position into the world.
  1512. // dist is the distance from the camera to the screen.
  1513. // NOTE! GAME_FOV_YAW needs to be the same value returned from CCSGameRules::DefaultFOV().
  1514. const float GAME_FOV_YAW = 90.0f;
  1515. float dist = ( width * 0.5f ) / tanf( GAME_FOV_YAW*0.5f );
  1516. Vector aimDirection = forward*dist + up*height*0.5f*adjustedY + right*width*0.5f*adjustedX;
  1517. aimDirection.NormalizeInPlace();
  1518. pPlayer->SetAimDirection( aimDirection );
  1519. Vector PureForward( 1.0f, 0.0f, 0.0f );
  1520. Vector PureUp( 0.0f, 0.0f, 1.0f);
  1521. Vector PureRight( 0.0f, -1.0f, 0.0f );
  1522. QAngle viewOffset;
  1523. Vector pureOffset = PureForward*dist + PureUp*height*0.5f*adjustedY + PureRight*width*0.5f*adjustedX;
  1524. VectorAngles( pureOffset, viewOffset );
  1525. if ( mc_force_aim_x.GetFloat() != 0.0f )
  1526. {
  1527. Vector eyePos = pPlayer->EyePosition();
  1528. Vector forcedAimPoint = forward*dist + up*height*0.5f*mc_force_aim_y.GetFloat() + right*width*0.5f*mc_force_aim_x.GetFloat();
  1529. const float DURATION = 0.15f;
  1530. DebugDrawLine( eyePos + forcedAimPoint, eyePos + forcedAimPoint + up*height*0.05f, 0,255,0, true, DURATION );
  1531. DebugDrawLine( eyePos + forcedAimPoint, eyePos + forcedAimPoint + right*width*0.05f, 255, 0, 0, true, DURATION );
  1532. DebugDrawLine( eyePos + forcedAimPoint, eyePos + forcedAimPoint - up*height*0.05f, 255, 255, 0, true, DURATION );
  1533. DebugDrawLine( eyePos + forcedAimPoint, eyePos + forcedAimPoint - right*width*0.05f, 255,0,255, true, DURATION );
  1534. forcedAimPoint.NormalizeInPlace();
  1535. pPlayer->SetAimDirection( forcedAimPoint );
  1536. Vector pureOffset2 = PureForward*dist + PureUp*height*0.5f*mc_force_aim_y.GetFloat() + PureRight*width*0.5f*mc_force_aim_x.GetFloat();
  1537. VectorAngles( pureOffset2, viewOffset );
  1538. }
  1539. pPlayer->SetEyeAngleOffset( viewOffset );
  1540. // Update the camera's angle.
  1541. if ( mc_zoomed_aim_style.GetInt() == 1 && pPlayer->m_bIsScoped )
  1542. {
  1543. QAngle aimDirectionAngles;
  1544. VectorAngles(aimDirection, aimDirectionAngles);
  1545. engine->SetViewAngles( aimDirectionAngles );
  1546. }
  1547. else
  1548. {
  1549. engine->SetViewAngles( s_referenceDirection );
  1550. }
  1551. s_lastCursorValueX = fX;
  1552. s_lastCursorValueY = fY;
  1553. cmd->aimdirection = pPlayer->GetAimDirection();
  1554. cmd->mousedx = deltaYaw;
  1555. cmd->mousedy = deltaPitch;
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. // Purpose: Apply joystick to CUserCmd creation
  1559. // Input : frametime -
  1560. // *cmd -
  1561. //-----------------------------------------------------------------------------
  1562. void CInput::JoyStickMove( float frametime, CUserCmd *cmd )
  1563. {
  1564. // complete initialization if first time in ( needed as cvars are not available at initialization time )
  1565. if ( !m_fJoystickAdvancedInit )
  1566. {
  1567. Joystick_Advanced( false );
  1568. }
  1569. // verify joystick is available and that the user wants to use it
  1570. if ( !in_joystick.GetInt() || 0 == inputsystem->GetJoystickCount() )
  1571. return;
  1572. // Skip out if vgui is active
  1573. if ( vgui::surface()->IsCursorVisible() )
  1574. return;
  1575. // Don't move if GameUI is visible
  1576. if ( enginevgui->IsGameUIVisible() )
  1577. return;
  1578. #ifdef PORTAL2
  1579. if ( IsRadialMenuOpen() )
  1580. return;
  1581. #endif
  1582. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1583. #if defined( INCLUDE_SCALEFORM )
  1584. if ( g_pScaleformUI->SlotDeniesInputToGame( SF_SS_SLOT( nSlot ) ) )
  1585. return;
  1586. #endif
  1587. PerUserInput_t &user = GetPerUser( nSlot );
  1588. // Sample the axes, apply the input, and consume sample time.
  1589. if ( user.m_flRemainingJoystickSampleTime > 0 )
  1590. {
  1591. frametime = MIN(user.m_flRemainingJoystickSampleTime, frametime);
  1592. user.m_flRemainingJoystickSampleTime -= frametime;
  1593. float forward, side, pitch, yaw;
  1594. bool bAbsoluteYaw, bAbsolutePitch;
  1595. JoyStickSampleAxes( forward, side, pitch, yaw, bAbsoluteYaw, bAbsolutePitch );
  1596. if ( !m_bControllerMode )
  1597. {
  1598. if ( fabsf(forward) > 0.1f || fabsf(side) > 0.1f || fabsf(pitch) > 0.1f || fabsf(yaw) > 0.1f )
  1599. {
  1600. m_bControllerMode = true;
  1601. }
  1602. }
  1603. if ( CAM_IsThirdPerson() && thirdperson_platformer.GetInt() )
  1604. {
  1605. JoyStickThirdPersonPlatformer( cmd, forward, side, pitch, yaw );
  1606. return;
  1607. }
  1608. float joyForwardMove, joySideMove;
  1609. JoyStickForwardSideControl( forward, side, joyForwardMove, joySideMove );
  1610. // Cache off the input sample values in case we run out of sample time.
  1611. user.m_flPreviousJoystickForwardMove = joyForwardMove;
  1612. user.m_flPreviousJoystickSideMove = joySideMove;
  1613. user.m_flPreviousJoystickYaw = yaw;
  1614. user.m_flPreviousJoystickPitch = pitch;
  1615. user.m_bPreviousJoystickUseAbsoluteYaw = bAbsoluteYaw;
  1616. user.m_bPreviousJoystickUseAbsolutePitch = bAbsolutePitch;
  1617. }
  1618. if ( JoyStickActive() )
  1619. {
  1620. // If we are using a motion controller, then we use the pointing device for updating the look direction.
  1621. if( inputsystem->MotionControllerActive())
  1622. {
  1623. MotionControllerMove( frametime, cmd );
  1624. }
  1625. else
  1626. {
  1627. JoyStickTurn( cmd,
  1628. user.m_flPreviousJoystickYaw,
  1629. user.m_flPreviousJoystickPitch,
  1630. frametime,
  1631. user.m_bPreviousJoystickUseAbsoluteYaw,
  1632. user.m_bPreviousJoystickUseAbsolutePitch );
  1633. }
  1634. JoyStickApplyMovement( cmd,
  1635. user.m_flPreviousJoystickForwardMove,
  1636. user.m_flPreviousJoystickSideMove );
  1637. }
  1638. }
  1639. //--------------------------------------------------------------
  1640. // Applies the calculated forward/side movement to the UserCmd
  1641. //--------------------------------------------------------------
  1642. void CInput::JoyStickApplyMovement( CUserCmd *cmd, float joyForwardMove, float joySideMove )
  1643. {
  1644. // apply player motion relative to screen space
  1645. if ( CAM_IsThirdPerson() && thirdperson_screenspace.GetInt() )
  1646. {
  1647. #ifdef INFESTED_DLL
  1648. float ideal_yaw = asw_cam_marine_yaw.GetFloat();
  1649. #else
  1650. float ideal_yaw = cam_idealyaw.GetFloat();
  1651. #endif
  1652. float ideal_sin = sin(DEG2RAD(ideal_yaw));
  1653. float ideal_cos = cos(DEG2RAD(ideal_yaw));
  1654. float side_movement = ideal_cos*joySideMove - ideal_sin*joyForwardMove;
  1655. float forward_movement = ideal_cos*joyForwardMove + ideal_sin*joySideMove;
  1656. cmd->forwardmove += forward_movement;
  1657. cmd->sidemove += side_movement;
  1658. }
  1659. else
  1660. {
  1661. cmd->forwardmove += joyForwardMove;
  1662. cmd->sidemove += joySideMove;
  1663. }
  1664. if ( IsPC() )
  1665. {
  1666. CCommand tmp;
  1667. if ( FloatMakePositive(joyForwardMove) >= joy_autosprint.GetFloat() || FloatMakePositive(joySideMove) >= joy_autosprint.GetFloat() )
  1668. {
  1669. KeyDown( &in_joyspeed, NULL );
  1670. }
  1671. else
  1672. {
  1673. KeyUp( &in_joyspeed, NULL );
  1674. }
  1675. }
  1676. }
  1677. float CInput::UpdateAndGetQuickTurnYaw( int nSlot, float frametime, float angle )
  1678. {
  1679. PerUserInput_t &user = GetPerUser( nSlot );
  1680. if ( user.m_flSpinFrameTime )
  1681. {
  1682. // apply specified yaw velocity until duration expires
  1683. float delta = frametime;
  1684. if ( user.m_flSpinFrameTime - delta <= 0 )
  1685. {
  1686. // effect expired, avoid floating point creep
  1687. delta = user.m_flSpinFrameTime;
  1688. user.m_flSpinFrameTime = 0;
  1689. }
  1690. else
  1691. {
  1692. user.m_flSpinFrameTime -= delta;
  1693. }
  1694. // Modify the angle if we're doing a quick turn.
  1695. angle = user.m_flSpinRate * delta;
  1696. }
  1697. // Update the spin rate
  1698. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer( nSlot );
  1699. if ( ( in_lookspin.GetPerUser( nSlot ).state & 2 ) && !user.m_flSpinFrameTime && pLocalPlayer && !pLocalPlayer->IsObserver() )
  1700. {
  1701. // user has actuated a new spin boost
  1702. float spinFrameTime = joy_lookspin_default.GetFloat();
  1703. user.m_flSpinFrameTime = spinFrameTime;
  1704. // yaw velocity is in last known direction
  1705. if ( user.m_flLastYawAngle >= 0 )
  1706. {
  1707. user.m_flSpinRate = 180.0f/spinFrameTime;
  1708. }
  1709. else
  1710. {
  1711. user.m_flSpinRate = -180.0f/spinFrameTime;
  1712. }
  1713. }
  1714. // Save off the last angle if non zero.
  1715. if ( angle != 0.0f )
  1716. {
  1717. // track angular direction
  1718. user.m_flLastYawAngle = angle;
  1719. }
  1720. return angle;
  1721. }