UsercmdGen.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Session_local.h"
  23. /*
  24. ================
  25. usercmd_t::ByteSwap
  26. ================
  27. */
  28. void usercmd_t::ByteSwap( void ) {
  29. angles[0] = LittleShort( angles[0] );
  30. angles[1] = LittleShort( angles[1] );
  31. angles[2] = LittleShort( angles[2] );
  32. sequence = LittleLong( sequence );
  33. }
  34. /*
  35. ================
  36. usercmd_t::operator==
  37. ================
  38. */
  39. bool usercmd_t::operator==( const usercmd_t &rhs ) const {
  40. return ( buttons == rhs.buttons &&
  41. forwardmove == rhs.forwardmove &&
  42. rightmove == rhs.rightmove &&
  43. upmove == rhs.upmove &&
  44. angles[0] == rhs.angles[0] &&
  45. angles[1] == rhs.angles[1] &&
  46. angles[2] == rhs.angles[2] &&
  47. impulse == rhs.impulse &&
  48. flags == rhs.flags &&
  49. mx == rhs.mx &&
  50. my == rhs.my );
  51. }
  52. const int KEY_MOVESPEED = 127;
  53. typedef enum {
  54. UB_NONE,
  55. UB_UP,
  56. UB_DOWN,
  57. UB_LEFT,
  58. UB_RIGHT,
  59. UB_FORWARD,
  60. UB_BACK,
  61. UB_LOOKUP,
  62. UB_LOOKDOWN,
  63. UB_STRAFE,
  64. UB_MOVELEFT,
  65. UB_MOVERIGHT,
  66. UB_BUTTON0,
  67. UB_BUTTON1,
  68. UB_BUTTON2,
  69. UB_BUTTON3,
  70. UB_BUTTON4,
  71. UB_BUTTON5,
  72. UB_BUTTON6,
  73. UB_BUTTON7,
  74. UB_ATTACK,
  75. UB_SPEED,
  76. UB_ZOOM,
  77. UB_SHOWSCORES,
  78. UB_MLOOK,
  79. UB_PICKER, //bc
  80. UB_ROTATE,
  81. UB_IMPULSE0,
  82. UB_IMPULSE1,
  83. UB_IMPULSE2,
  84. UB_IMPULSE3,
  85. UB_IMPULSE4,
  86. UB_IMPULSE5,
  87. UB_IMPULSE6,
  88. UB_IMPULSE7,
  89. UB_IMPULSE8,
  90. UB_IMPULSE9,
  91. UB_IMPULSE10,
  92. UB_IMPULSE11,
  93. UB_IMPULSE12,
  94. UB_IMPULSE13,
  95. UB_IMPULSE14,
  96. UB_IMPULSE15,
  97. UB_IMPULSE16,
  98. UB_IMPULSE17,
  99. UB_IMPULSE18,
  100. UB_IMPULSE19,
  101. UB_IMPULSE20,
  102. UB_IMPULSE21,
  103. UB_IMPULSE22,
  104. UB_IMPULSE23,
  105. UB_IMPULSE24,
  106. UB_IMPULSE25,
  107. UB_IMPULSE26,
  108. UB_IMPULSE27,
  109. UB_IMPULSE28,
  110. UB_IMPULSE29,
  111. UB_IMPULSE30,
  112. UB_IMPULSE31,
  113. UB_IMPULSE32,
  114. UB_IMPULSE33,
  115. UB_IMPULSE34,
  116. UB_IMPULSE35,
  117. UB_IMPULSE36,
  118. UB_IMPULSE37,
  119. UB_IMPULSE38,
  120. UB_IMPULSE39,
  121. UB_IMPULSE40,
  122. UB_IMPULSE41,
  123. UB_IMPULSE42,
  124. UB_IMPULSE43,
  125. UB_IMPULSE44,
  126. UB_IMPULSE45,
  127. UB_IMPULSE46,
  128. UB_IMPULSE47,
  129. UB_IMPULSE48,
  130. UB_IMPULSE49,
  131. UB_IMPULSE50,
  132. UB_IMPULSE51,
  133. UB_IMPULSE52,
  134. UB_IMPULSE53,
  135. UB_IMPULSE54,
  136. UB_IMPULSE55,
  137. UB_IMPULSE56,
  138. UB_IMPULSE57,
  139. UB_IMPULSE58,
  140. UB_IMPULSE59,
  141. UB_IMPULSE60,
  142. UB_IMPULSE61,
  143. UB_IMPULSE62,
  144. UB_IMPULSE63,
  145. UB_MAX_BUTTONS
  146. } usercmdButton_t;
  147. typedef struct {
  148. const char *string;
  149. usercmdButton_t button;
  150. } userCmdString_t;
  151. userCmdString_t userCmdStrings[] = {
  152. { "_moveUp", UB_UP },
  153. { "_moveDown", UB_DOWN },
  154. { "_left", UB_LEFT },
  155. { "_right", UB_RIGHT },
  156. { "_forward", UB_FORWARD },
  157. { "_back", UB_BACK },
  158. { "_lookUp", UB_LOOKUP },
  159. { "_lookDown", UB_LOOKDOWN },
  160. { "_strafe", UB_STRAFE },
  161. { "_moveLeft", UB_MOVELEFT },
  162. { "_moveRight", UB_MOVERIGHT },
  163. { "_attack", UB_ATTACK },
  164. { "_speed", UB_SPEED },
  165. { "_zoom", UB_ZOOM },
  166. { "_showScores", UB_SHOWSCORES },
  167. { "_mlook", UB_MLOOK },
  168. { "_picker", UB_PICKER }, //bc
  169. { "_rotate", UB_ROTATE },
  170. { "_button0", UB_BUTTON0 },
  171. { "_button1", UB_BUTTON1 },
  172. { "_button2", UB_BUTTON2 },
  173. { "_button3", UB_BUTTON3 },
  174. { "_button4", UB_BUTTON4 },
  175. { "_button5", UB_BUTTON5 },
  176. { "_button6", UB_BUTTON6 },
  177. { "_button7", UB_BUTTON7 },
  178. { "_impulse0", UB_IMPULSE0 },
  179. { "_impulse1", UB_IMPULSE1 },
  180. { "_impulse2", UB_IMPULSE2 },
  181. { "_impulse3", UB_IMPULSE3 },
  182. { "_impulse4", UB_IMPULSE4 },
  183. { "_impulse5", UB_IMPULSE5 },
  184. { "_impulse6", UB_IMPULSE6 },
  185. { "_impulse7", UB_IMPULSE7 },
  186. { "_impulse8", UB_IMPULSE8 },
  187. { "_impulse9", UB_IMPULSE9 },
  188. { "_impulse10", UB_IMPULSE10 },
  189. { "_impulse11", UB_IMPULSE11 },
  190. { "_impulse12", UB_IMPULSE12 },
  191. { "_impulse13", UB_IMPULSE13 },
  192. { "_impulse14", UB_IMPULSE14 },
  193. { "_impulse15", UB_IMPULSE15 },
  194. { "_impulse16", UB_IMPULSE16 },
  195. { "_impulse17", UB_IMPULSE17 },
  196. { "_impulse18", UB_IMPULSE18 },
  197. { "_impulse19", UB_IMPULSE19 },
  198. { "_impulse20", UB_IMPULSE20 },
  199. { "_impulse21", UB_IMPULSE21 },
  200. { "_impulse22", UB_IMPULSE22 },
  201. { "_impulse23", UB_IMPULSE23 },
  202. { "_impulse24", UB_IMPULSE24 },
  203. { "_impulse25", UB_IMPULSE25 },
  204. { "_impulse26", UB_IMPULSE26 },
  205. { "_impulse27", UB_IMPULSE27 },
  206. { "_impulse28", UB_IMPULSE28 },
  207. { "_impulse29", UB_IMPULSE29 },
  208. { "_impulse30", UB_IMPULSE30 },
  209. { "_impulse31", UB_IMPULSE31 },
  210. { "_impulse32", UB_IMPULSE32 },
  211. { "_impulse33", UB_IMPULSE33 },
  212. { "_impulse34", UB_IMPULSE34 },
  213. { "_impulse35", UB_IMPULSE35 },
  214. { "_impulse36", UB_IMPULSE36 },
  215. { "_impulse37", UB_IMPULSE37 },
  216. { "_impulse38", UB_IMPULSE38 },
  217. { "_impulse39", UB_IMPULSE39 },
  218. { "_impulse40", UB_IMPULSE40 },
  219. { "_impulse41", UB_IMPULSE41 },
  220. { "_impulse42", UB_IMPULSE42 },
  221. { "_impulse43", UB_IMPULSE43 },
  222. { "_impulse44", UB_IMPULSE44 },
  223. { "_impulse45", UB_IMPULSE45 },
  224. { "_impulse46", UB_IMPULSE46 },
  225. { "_impulse47", UB_IMPULSE47 },
  226. { "_impulse48", UB_IMPULSE48 },
  227. { "_impulse49", UB_IMPULSE49 },
  228. { "_impulse50", UB_IMPULSE50 },
  229. { "_impulse51", UB_IMPULSE51 },
  230. { "_impulse52", UB_IMPULSE52 },
  231. { "_impulse53", UB_IMPULSE53 },
  232. { "_impulse54", UB_IMPULSE54 },
  233. { "_impulse55", UB_IMPULSE55 },
  234. { "_impulse56", UB_IMPULSE56 },
  235. { "_impulse57", UB_IMPULSE57 },
  236. { "_impulse58", UB_IMPULSE58 },
  237. { "_impulse59", UB_IMPULSE59 },
  238. { "_impulse60", UB_IMPULSE60 },
  239. { "_impulse61", UB_IMPULSE61 },
  240. { "_impulse62", UB_IMPULSE62 },
  241. { "_impulse63", UB_IMPULSE63 },
  242. { NULL, UB_NONE },
  243. };
  244. class buttonState_t {
  245. public:
  246. int on;
  247. bool held;
  248. buttonState_t() { Clear(); };
  249. void Clear( void );
  250. void SetKeyState( int keystate, bool toggle );
  251. };
  252. /*
  253. ================
  254. buttonState_t::Clear
  255. ================
  256. */
  257. void buttonState_t::Clear( void ) {
  258. held = false;
  259. on = 0;
  260. }
  261. /*
  262. ================
  263. buttonState_t::SetKeyState
  264. ================
  265. */
  266. void buttonState_t::SetKeyState( int keystate, bool toggle ) {
  267. if ( !toggle ) {
  268. held = false;
  269. on = keystate;
  270. } else if ( !keystate ) {
  271. held = false;
  272. } else if ( !held ) {
  273. held = true;
  274. on ^= 1;
  275. }
  276. }
  277. const int NUM_USER_COMMANDS = sizeof(userCmdStrings) / sizeof(userCmdString_t);
  278. const int MAX_CHAT_BUFFER = 127;
  279. class idUsercmdGenLocal : public idUsercmdGen {
  280. public:
  281. idUsercmdGenLocal( void );
  282. void Init( void );
  283. void InitForNewMap( void );
  284. void Shutdown( void );
  285. void Clear( void );
  286. void ClearAngles( void );
  287. usercmd_t TicCmd( int ticNumber );
  288. void InhibitUsercmd( inhibit_t subsystem, bool inhibit );
  289. void UsercmdInterrupt( void );
  290. int CommandStringUsercmdData( const char *cmdString );
  291. int GetNumUserCommands( void );
  292. const char * GetUserCommandName( int index );
  293. void MouseState( int *x, int *y, int *button, bool *down );
  294. int ButtonState( int key );
  295. int KeyState( int key );
  296. usercmd_t GetDirectUsercmd( void );
  297. private:
  298. void MakeCurrent( void );
  299. void InitCurrent( void );
  300. bool Inhibited( void );
  301. void AdjustAngles( void );
  302. void KeyMove( void );
  303. void CircleToSquare( float & axis_x, float & axis_y ) const;
  304. void HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive );
  305. void JoystickMove();
  306. void MouseMove( void );
  307. void CmdButtons( void );
  308. void Mouse( void );
  309. void Keyboard( void );
  310. void Joystick( void );
  311. void Key( int keyNum, bool down );
  312. idVec3 viewangles;
  313. int flags;
  314. int impulse;
  315. buttonState_t toggled_crouch;
  316. buttonState_t toggled_run;
  317. buttonState_t toggled_zoom;
  318. int buttonState[UB_MAX_BUTTONS];
  319. bool keyState[K_LAST_KEY];
  320. int inhibitCommands; // true when in console or menu locally
  321. int lastCommandTime;
  322. bool initialized;
  323. usercmd_t cmd; // the current cmd being built
  324. usercmd_t buffered[MAX_BUFFERED_USERCMD];
  325. int continuousMouseX, continuousMouseY; // for gui event generatioin, never zerod
  326. int mouseButton; // for gui event generatioin
  327. bool mouseDown;
  328. int mouseDx, mouseDy; // added to by mouse events
  329. float joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
  330. int pollTime;
  331. int lastPollTime;
  332. float lastLookValuePitch;
  333. float lastLookValueYaw;
  334. typedef unsigned char boolean; // from jpeglib.h
  335. bool heldJump;
  336. static idCVar in_yawSpeed;
  337. static idCVar in_pitchSpeed;
  338. static idCVar in_angleSpeedKey;
  339. static idCVar in_freeLook;
  340. static idCVar in_alwaysRun;
  341. static idCVar in_toggleRun;
  342. static idCVar in_toggleCrouch;
  343. static idCVar in_toggleZoom;
  344. static idCVar sensitivity;
  345. static idCVar m_pitch;
  346. static idCVar m_yaw;
  347. static idCVar m_strafeScale;
  348. static idCVar m_smooth;
  349. static idCVar m_strafeSmooth;
  350. static idCVar m_showMouseRate;
  351. };
  352. idCVar idUsercmdGenLocal::in_yawSpeed( "in_yawspeed", "140", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "yaw change speed when holding down _left or _right button" );
  353. idCVar idUsercmdGenLocal::in_pitchSpeed( "in_pitchspeed", "140", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "pitch change speed when holding down look _lookUp or _lookDown button" );
  354. idCVar idUsercmdGenLocal::in_angleSpeedKey( "in_anglespeedkey", "1.5", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "angle change scale when holding down _speed button" );
  355. idCVar idUsercmdGenLocal::in_freeLook( "in_freeLook", "1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "look around with mouse (reverse _mlook button)" );
  356. idCVar idUsercmdGenLocal::in_alwaysRun( "in_alwaysRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "always run (reverse _speed button) - only in MP" );
  357. idCVar idUsercmdGenLocal::in_toggleRun( "in_toggleRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _speed button toggles run on/off - only in MP" );
  358. idCVar idUsercmdGenLocal::in_toggleCrouch( "in_toggleCrouch", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _movedown button toggles player crouching/standing" );
  359. idCVar idUsercmdGenLocal::in_toggleZoom( "in_toggleZoom", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _zoom button toggles zoom on/off" );
  360. idCVar idUsercmdGenLocal::sensitivity( "sensitivity", "5", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse view sensitivity" );
  361. idCVar idUsercmdGenLocal::m_pitch( "m_pitch", "0.022", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse pitch scale" );
  362. idCVar idUsercmdGenLocal::m_yaw( "m_yaw", "0.022", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse yaw scale" );
  363. idCVar idUsercmdGenLocal::m_strafeScale( "m_strafeScale", "6.25", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse strafe movement scale" );
  364. idCVar idUsercmdGenLocal::m_smooth( "m_smooth", "1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse viewing", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
  365. idCVar idUsercmdGenLocal::m_strafeSmooth( "m_strafeSmooth", "4", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse moving", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
  366. idCVar idUsercmdGenLocal::m_showMouseRate( "m_showMouseRate", "0", CVAR_SYSTEM | CVAR_BOOL, "shows mouse movement" );
  367. idCVar joy_mergedThreshold( "joy_mergedThreshold", "1", CVAR_BOOL | CVAR_ARCHIVE, "If the thresholds aren't merged, you drift more off center" );
  368. idCVar joy_newCode( "joy_newCode", "0", CVAR_BOOL | CVAR_ARCHIVE, "Use the new codepath" );
  369. idCVar joy_triggerThreshold( "joy_triggerThreshold", "0.05", CVAR_FLOAT | CVAR_ARCHIVE, "how far the joystick triggers have to be pressed before they register as down" );
  370. idCVar joy_deadZone( "joy_deadZone", "0.4", CVAR_FLOAT | CVAR_ARCHIVE, "specifies how large the dead-zone is on the joystick" );
  371. idCVar joy_range( "joy_range", "1.0", CVAR_FLOAT | CVAR_ARCHIVE, "allow full range to be mapped to a smaller offset" );
  372. idCVar joy_gammaLook( "joy_gammaLook", "1", CVAR_INTEGER | CVAR_ARCHIVE, "use a log curve instead of a power curve for movement" );
  373. idCVar joy_powerScale( "joy_powerScale", "2", CVAR_FLOAT | CVAR_ARCHIVE, "Raise joystick values to this power" );
  374. idCVar joy_pitchSpeed( "joy_pitchSpeed", "130", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing up or down on the joystick", 60, 600 );
  375. idCVar joy_yawSpeed( "joy_yawSpeed", "240", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing left or right on the joystick", 60, 600 );
  376. // these were a bad idea!
  377. idCVar joy_dampenLook( "joy_dampenLook", "1", CVAR_BOOL | CVAR_ARCHIVE, "Do not allow full acceleration on look" );
  378. idCVar joy_deltaPerMSLook( "joy_deltaPerMSLook", "0.003", CVAR_FLOAT | CVAR_ARCHIVE, "Max amount to be added on look per MS" );
  379. idCVar in_useJoystick( "in_useJoystick", "0", CVAR_ARCHIVE | CVAR_BOOL, "enables/disables the gamepad for PC use" );
  380. idCVar in_invertLook( "in_invertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
  381. idCVar in_mouseInvertLook( "in_mouseInvertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
  382. static idUsercmdGenLocal localUsercmdGen;
  383. idUsercmdGen *usercmdGen = &localUsercmdGen;
  384. /*
  385. ================
  386. idUsercmdGenLocal::idUsercmdGenLocal
  387. ================
  388. */
  389. idUsercmdGenLocal::idUsercmdGenLocal( void ) {
  390. lastCommandTime = 0;
  391. initialized = false;
  392. flags = 0;
  393. impulse = 0;
  394. toggled_crouch.Clear();
  395. toggled_run.Clear();
  396. toggled_zoom.Clear();
  397. toggled_run.on = in_alwaysRun.GetBool();
  398. ClearAngles();
  399. Clear();
  400. }
  401. /*
  402. ================
  403. idUsercmdGenLocal::InhibitUsercmd
  404. ================
  405. */
  406. void idUsercmdGenLocal::InhibitUsercmd( inhibit_t subsystem, bool inhibit ) {
  407. if ( inhibit ) {
  408. inhibitCommands |= 1 << subsystem;
  409. } else {
  410. inhibitCommands &= ( 0xffffffff ^ ( 1 << subsystem ) );
  411. }
  412. }
  413. /*
  414. ===============
  415. idUsercmdGenLocal::ButtonState
  416. Returns (the fraction of the frame) that the key was down
  417. ===============
  418. */
  419. int idUsercmdGenLocal::ButtonState( int key ) {
  420. if ( key<0 || key>=UB_MAX_BUTTONS ) {
  421. return -1;
  422. }
  423. return ( buttonState[key] > 0 ) ? 1 : 0;
  424. }
  425. /*
  426. ===============
  427. idUsercmdGenLocal::KeyState
  428. Returns (the fraction of the frame) that the key was down
  429. bk20060111
  430. ===============
  431. */
  432. int idUsercmdGenLocal::KeyState( int key ) {
  433. if ( key<0 || key>=K_LAST_KEY ) {
  434. return -1;
  435. }
  436. return ( keyState[key] ) ? 1 : 0;
  437. }
  438. //=====================================================================
  439. /*
  440. ================
  441. idUsercmdGenLocal::GetNumUserCommands
  442. ================
  443. */
  444. int idUsercmdGenLocal::GetNumUserCommands( void ) {
  445. return NUM_USER_COMMANDS;
  446. }
  447. /*
  448. ================
  449. idUsercmdGenLocal::GetNumUserCommands
  450. ================
  451. */
  452. const char *idUsercmdGenLocal::GetUserCommandName( int index ) {
  453. if (index >= 0 && index < NUM_USER_COMMANDS) {
  454. return userCmdStrings[index].string;
  455. }
  456. return "";
  457. }
  458. /*
  459. ================
  460. idUsercmdGenLocal::Inhibited
  461. is user cmd generation inhibited
  462. ================
  463. */
  464. bool idUsercmdGenLocal::Inhibited( void ) {
  465. return ( inhibitCommands != 0);
  466. }
  467. /*
  468. ================
  469. idUsercmdGenLocal::AdjustAngles
  470. Moves the local angle positions
  471. ================
  472. */
  473. void idUsercmdGenLocal::AdjustAngles( void ) {
  474. float speed;
  475. if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) {
  476. speed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat();
  477. } else {
  478. speed = idMath::M_MS2SEC * USERCMD_MSEC;
  479. }
  480. if ( !ButtonState( UB_STRAFE ) ) {
  481. viewangles[YAW] -= speed * in_yawSpeed.GetFloat() * ButtonState( UB_RIGHT );
  482. viewangles[YAW] += speed * in_yawSpeed.GetFloat() * ButtonState( UB_LEFT );
  483. }
  484. viewangles[PITCH] -= speed * in_pitchSpeed.GetFloat() * ButtonState( UB_LOOKUP );
  485. viewangles[PITCH] += speed * in_pitchSpeed.GetFloat() * ButtonState( UB_LOOKDOWN );
  486. }
  487. /*
  488. ================
  489. idUsercmdGenLocal::KeyMove
  490. Sets the usercmd_t based on key states
  491. ================
  492. */
  493. void idUsercmdGenLocal::KeyMove( void ) {
  494. int forward, side, up;
  495. forward = 0;
  496. side = 0;
  497. up = 0;
  498. if ( ButtonState( UB_STRAFE ) ) {
  499. side += KEY_MOVESPEED * ButtonState( UB_RIGHT );
  500. side -= KEY_MOVESPEED * ButtonState( UB_LEFT );
  501. }
  502. side += KEY_MOVESPEED * ButtonState( UB_MOVERIGHT );
  503. side -= KEY_MOVESPEED * ButtonState( UB_MOVELEFT );
  504. up -= KEY_MOVESPEED * toggled_crouch.on;
  505. if (!in_toggleCrouch.GetBool())
  506. {
  507. //default behavior.
  508. up += KEY_MOVESPEED * ButtonState( UB_UP );
  509. }
  510. else
  511. {
  512. //togglecrouch behavior.
  513. if (ButtonState( UB_UP ) && toggled_crouch.on)
  514. {
  515. heldJump = true;
  516. toggled_crouch.Clear();
  517. }
  518. if (!ButtonState( UB_UP ) && heldJump)
  519. {
  520. heldJump = false;
  521. }
  522. if (ButtonState( UB_UP ) && !heldJump)
  523. {
  524. up += KEY_MOVESPEED * ButtonState( UB_UP );
  525. }
  526. }
  527. forward += KEY_MOVESPEED * ButtonState( UB_FORWARD );
  528. forward -= KEY_MOVESPEED * ButtonState( UB_BACK );
  529. // only set each movement variable if its unset at this point.
  530. // NOTE: joystick input happens before this.
  531. if (cmd.forwardmove == 0) {
  532. cmd.forwardmove = idMath::ClampChar( forward );
  533. }
  534. if (cmd.rightmove == 0) {
  535. cmd.rightmove = idMath::ClampChar( side );
  536. }
  537. if (cmd.upmove == 0) {
  538. cmd.upmove = idMath::ClampChar( up );
  539. }
  540. }
  541. /*
  542. =================
  543. idUsercmdGenLocal::MouseMove
  544. =================
  545. */
  546. void idUsercmdGenLocal::MouseMove( void ) {
  547. float mx, my, strafeMx, strafeMy;
  548. static int history[8][2];
  549. static int historyCounter;
  550. int i;
  551. history[historyCounter&7][0] = mouseDx;
  552. history[historyCounter&7][1] = mouseDy;
  553. // allow mouse movement to be smoothed together
  554. int smooth = m_smooth.GetInteger();
  555. if ( smooth < 1 ) {
  556. smooth = 1;
  557. }
  558. if ( smooth > 8 ) {
  559. smooth = 8;
  560. }
  561. mx = 0;
  562. my = 0;
  563. for ( i = 0 ; i < smooth ; i++ ) {
  564. mx += history[ ( historyCounter - i + 8 ) & 7 ][0];
  565. my += history[ ( historyCounter - i + 8 ) & 7 ][1];
  566. }
  567. mx /= smooth;
  568. my /= smooth;
  569. // use a larger smoothing for strafing
  570. smooth = m_strafeSmooth.GetInteger();
  571. if ( smooth < 1 ) {
  572. smooth = 1;
  573. }
  574. if ( smooth > 8 ) {
  575. smooth = 8;
  576. }
  577. strafeMx = 0;
  578. strafeMy = 0;
  579. for ( i = 0 ; i < smooth ; i++ ) {
  580. strafeMx += history[ ( historyCounter - i + 8 ) & 7 ][0];
  581. strafeMy += history[ ( historyCounter - i + 8 ) & 7 ][1];
  582. }
  583. strafeMx /= smooth;
  584. strafeMy /= smooth;
  585. historyCounter++;
  586. if ( idMath::Fabs( mx ) > 1000 || idMath::Fabs( my ) > 1000 ) {
  587. Sys_DebugPrintf( "idUsercmdGenLocal::MouseMove: Ignoring ridiculous mouse delta.\n" );
  588. mx = my = 0;
  589. }
  590. mx *= sensitivity.GetFloat();
  591. my *= sensitivity.GetFloat();
  592. if ( m_showMouseRate.GetBool() ) {
  593. Sys_DebugPrintf( "[%3i %3i = %5.1f %5.1f = %5.1f %5.1f] ", mouseDx, mouseDy, mx, my, strafeMx, strafeMy );
  594. }
  595. mouseDx = 0;
  596. mouseDy = 0;
  597. if ( !strafeMx && !strafeMy ) {
  598. return;
  599. }
  600. if ( ButtonState( UB_STRAFE ) || !( cmd.buttons & BUTTON_MLOOK ) ) {
  601. // add mouse X/Y movement to cmd
  602. strafeMx *= m_strafeScale.GetFloat();
  603. strafeMy *= m_strafeScale.GetFloat();
  604. // clamp as a vector, instead of separate floats
  605. float len = sqrt( strafeMx * strafeMx + strafeMy * strafeMy );
  606. if ( len > 127 ) {
  607. strafeMx = strafeMx * 127 / len;
  608. strafeMy = strafeMy * 127 / len;
  609. }
  610. }
  611. if ( !ButtonState( UB_STRAFE ) ) {
  612. viewangles[YAW] -= m_yaw.GetFloat() * mx;
  613. } else {
  614. cmd.rightmove = idMath::ClampChar( (int)(cmd.rightmove + strafeMx) );
  615. }
  616. if ( !ButtonState( UB_STRAFE ) && ( cmd.buttons & BUTTON_MLOOK ) ) {
  617. viewangles[PITCH] += m_pitch.GetFloat() * ( in_mouseInvertLook.GetBool() ? -my : my );
  618. } else {
  619. cmd.forwardmove = idMath::ClampChar( (int)(cmd.forwardmove - strafeMy) );
  620. }
  621. }
  622. /*
  623. ========================
  624. idUsercmdGenLocal::CircleToSquare
  625. ========================
  626. */
  627. void idUsercmdGenLocal::CircleToSquare( float & axis_x, float & axis_y ) const {
  628. // bring everything in the first quadrant
  629. bool flip_x = false;
  630. if ( axis_x < 0.0f ) {
  631. flip_x = true;
  632. axis_x *= -1.0f;
  633. }
  634. bool flip_y = false;
  635. if ( axis_y < 0.0f ) {
  636. flip_y = true;
  637. axis_y *= -1.0f;
  638. }
  639. // swap the two axes so we project against the vertical line X = 1
  640. bool swap = false;
  641. if ( axis_y > axis_x ) {
  642. float tmp = axis_x;
  643. axis_x = axis_y;
  644. axis_y = tmp;
  645. swap = true;
  646. }
  647. if ( axis_x < 0.001f ) {
  648. // on one of the axes where no correction is needed
  649. return;
  650. }
  651. // length (max 1.0f at the unit circle)
  652. float len = idMath::Sqrt( axis_x * axis_x + axis_y * axis_y );
  653. if ( len > 1.0f ) {
  654. len = 1.0f;
  655. }
  656. // thales
  657. float axis_y_us = axis_y / axis_x;
  658. // use a power curve to shift the correction to happen closer to the unit circle
  659. float correctionRatio = Square( len );
  660. axis_x += correctionRatio * ( len - axis_x );
  661. axis_y += correctionRatio * ( axis_y_us - axis_y );
  662. // go back through the symmetries
  663. if ( swap ) {
  664. float tmp = axis_x;
  665. axis_x = axis_y;
  666. axis_y = tmp;
  667. }
  668. if ( flip_x ) {
  669. axis_x *= -1.0f;
  670. }
  671. if ( flip_y ) {
  672. axis_y *= -1.0f;
  673. }
  674. }
  675. /*
  676. ========================
  677. idUsercmdGenLocal::HandleJoystickAxis
  678. ========================
  679. */
  680. void idUsercmdGenLocal::HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive ) {
  681. if ( ( unclampedValue > 0.0f ) && !positive ) {
  682. return;
  683. }
  684. if ( ( unclampedValue < 0.0f ) && positive ) {
  685. return;
  686. }
  687. float value = 0.0f;
  688. bool pressed = false;
  689. if ( unclampedValue > threshold ) {
  690. value = idMath::Fabs( ( unclampedValue - threshold ) / ( 1.0f - threshold ) );
  691. pressed = true;
  692. } else if ( unclampedValue < -threshold ) {
  693. value = idMath::Fabs( ( unclampedValue + threshold ) / ( 1.0f - threshold ) );
  694. pressed = true;
  695. }
  696. int action = idKeyInput::GetUsercmdAction( keyNum );
  697. if ( action >= UB_ATTACK ) {
  698. Key( keyNum, pressed );
  699. return;
  700. }
  701. if ( !pressed ) {
  702. return;
  703. }
  704. float lookValue = 0.0f;
  705. if ( joy_gammaLook.GetBool() ) {
  706. lookValue = idMath::Pow( 1.04712854805f, value * 100.0f ) * 0.01f;
  707. } else {
  708. lookValue = idMath::Pow( value, joy_powerScale.GetFloat() );
  709. }
  710. #if 0 // TODO: aim assist maybe.
  711. idGame * game = common->Game();
  712. if ( game != NULL ) {
  713. lookValue *= game->GetAimAssistSensitivity();
  714. }
  715. #endif
  716. switch ( action ) {
  717. case UB_FORWARD: {
  718. float move = (float)cmd.forwardmove + ( KEY_MOVESPEED * value );
  719. cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
  720. break;
  721. }
  722. case UB_BACK: {
  723. float move = (float)cmd.forwardmove - ( KEY_MOVESPEED * value );
  724. cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
  725. break;
  726. }
  727. case UB_MOVELEFT: {
  728. float move = (float)cmd.rightmove - ( KEY_MOVESPEED * value );
  729. cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
  730. break;
  731. }
  732. case UB_MOVERIGHT: {
  733. float move = (float)cmd.rightmove + ( KEY_MOVESPEED * value );
  734. cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
  735. break;
  736. }
  737. case UB_LOOKUP: {
  738. if ( joy_dampenLook.GetBool() ) {
  739. lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
  740. lastLookValuePitch = lookValue;
  741. }
  742. float invertPitch = in_invertLook.GetBool() ? -1.0f : 1.0f;
  743. viewangles[PITCH] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
  744. break;
  745. }
  746. case UB_LOOKDOWN: {
  747. if ( joy_dampenLook.GetBool() ) {
  748. lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
  749. lastLookValuePitch = lookValue;
  750. }
  751. float invertPitch = in_invertLook.GetBool() ? -1.0f : 1.0f;
  752. viewangles[PITCH] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
  753. break;
  754. }
  755. case UB_LEFT: {
  756. if ( joy_dampenLook.GetBool() ) {
  757. lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
  758. lastLookValueYaw = lookValue;
  759. }
  760. viewangles[YAW] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
  761. break;
  762. }
  763. case UB_RIGHT: {
  764. if ( joy_dampenLook.GetBool() ) {
  765. lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
  766. lastLookValueYaw = lookValue;
  767. }
  768. viewangles[YAW] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
  769. break;
  770. }
  771. }
  772. }
  773. /*
  774. =================
  775. idUsercmdGenLocal::JoystickMove
  776. =================
  777. */
  778. void idUsercmdGenLocal::JoystickMove() {
  779. float threshold = joy_deadZone.GetFloat();
  780. float triggerThreshold = joy_triggerThreshold.GetFloat();
  781. float axis_y = joystickAxis[ AXIS_LEFT_Y ];
  782. float axis_x = joystickAxis[ AXIS_LEFT_X ];
  783. CircleToSquare( axis_x, axis_y );
  784. HandleJoystickAxis( K_JOY_STICK1_UP, axis_y, threshold, false );
  785. HandleJoystickAxis( K_JOY_STICK1_DOWN, axis_y, threshold, true );
  786. HandleJoystickAxis( K_JOY_STICK1_LEFT, axis_x, threshold, false );
  787. HandleJoystickAxis( K_JOY_STICK1_RIGHT, axis_x, threshold, true );
  788. axis_y = joystickAxis[ AXIS_RIGHT_Y ];
  789. axis_x = joystickAxis[ AXIS_RIGHT_X ];
  790. CircleToSquare( axis_x, axis_y );
  791. HandleJoystickAxis( K_JOY_STICK2_UP, axis_y, threshold, false );
  792. HandleJoystickAxis( K_JOY_STICK2_DOWN, axis_y, threshold, true );
  793. HandleJoystickAxis( K_JOY_STICK2_LEFT, axis_x, threshold, false );
  794. HandleJoystickAxis( K_JOY_STICK2_RIGHT, axis_x, threshold, true );
  795. HandleJoystickAxis( K_JOY_TRIGGER1, joystickAxis[ AXIS_LEFT_TRIG ], triggerThreshold, true );
  796. HandleJoystickAxis( K_JOY_TRIGGER2, joystickAxis[ AXIS_RIGHT_TRIG ], triggerThreshold, true );
  797. }
  798. /*
  799. ==============
  800. idUsercmdGenLocal::CmdButtons
  801. ==============
  802. */
  803. void idUsercmdGenLocal::CmdButtons( void ) {
  804. int i;
  805. cmd.buttons = 0;
  806. // figure button bits
  807. for (i = 0 ; i <= 7 ; i++) {
  808. if ( ButtonState( (usercmdButton_t)( UB_BUTTON0 + i ) ) ) {
  809. cmd.buttons |= 1 << i;
  810. }
  811. }
  812. // check the attack button
  813. if ( ButtonState( UB_ATTACK ) ) {
  814. cmd.buttons |= BUTTON_ATTACK;
  815. }
  816. // check the run button
  817. if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) {
  818. cmd.buttons |= BUTTON_RUN;
  819. }
  820. // check the zoom button
  821. if ( toggled_zoom.on ) {
  822. cmd.buttons |= BUTTON_ZOOM;
  823. }
  824. // check the scoreboard button
  825. if ( ButtonState( UB_SHOWSCORES ) || ButtonState( UB_IMPULSE19 ) ) {
  826. // the button is toggled in SP mode as well but without effect
  827. cmd.buttons |= BUTTON_SCORES;
  828. }
  829. //bc
  830. if ( ButtonState ( UB_PICKER ))
  831. {
  832. cmd.buttons |= BUTTON_PICKER;
  833. }
  834. if ( ButtonState ( UB_ROTATE ))
  835. {
  836. cmd.buttons |= BUTTON_ROTATE;
  837. }
  838. // check the mouse look button
  839. if ( ButtonState( UB_MLOOK ) ^ in_freeLook.GetInteger() ) {
  840. cmd.buttons |= BUTTON_MLOOK;
  841. }
  842. }
  843. /*
  844. ================
  845. idUsercmdGenLocal::InitCurrent
  846. inits the current command for this frame
  847. ================
  848. */
  849. void idUsercmdGenLocal::InitCurrent( void ) {
  850. memset( &cmd, 0, sizeof( cmd ) );
  851. cmd.flags = flags;
  852. cmd.impulse = impulse;
  853. cmd.buttons |= ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ? BUTTON_RUN : 0;
  854. cmd.buttons |= in_freeLook.GetBool() ? BUTTON_MLOOK : 0;
  855. }
  856. /*
  857. ================
  858. idUsercmdGenLocal::MakeCurrent
  859. creates the current command for this frame
  860. ================
  861. */
  862. void idUsercmdGenLocal::MakeCurrent( void ) {
  863. idVec3 oldAngles;
  864. int i;
  865. oldAngles = viewangles;
  866. if ( !Inhibited() ) {
  867. // update toggled key states
  868. toggled_crouch.SetKeyState( ButtonState( UB_DOWN ), in_toggleCrouch.GetBool() );
  869. toggled_run.SetKeyState( ButtonState( UB_SPEED ), in_toggleRun.GetBool() && idAsyncNetwork::IsActive() );
  870. toggled_zoom.SetKeyState( ButtonState( UB_ZOOM ), in_toggleZoom.GetBool() );
  871. // keyboard angle adjustment
  872. AdjustAngles();
  873. // get basic movement from joystick
  874. JoystickMove();
  875. // set button bits
  876. CmdButtons();
  877. // get basic movement from keyboard
  878. KeyMove();
  879. // get basic movement from mouse
  880. MouseMove();
  881. // check to make sure the angles haven't wrapped
  882. if ( viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
  883. viewangles[PITCH] = oldAngles[PITCH] + 90;
  884. } else if ( oldAngles[PITCH] - viewangles[PITCH] > 90 ) {
  885. viewangles[PITCH] = oldAngles[PITCH] - 90;
  886. }
  887. } else {
  888. mouseDx = 0;
  889. mouseDy = 0;
  890. }
  891. for ( i = 0; i < 3; i++ ) {
  892. cmd.angles[i] = ANGLE2SHORT( viewangles[i] );
  893. }
  894. cmd.mx = continuousMouseX;
  895. cmd.my = continuousMouseY;
  896. flags = cmd.flags;
  897. impulse = cmd.impulse;
  898. }
  899. //=====================================================================
  900. /*
  901. ================
  902. idUsercmdGenLocal::CommandStringUsercmdData
  903. Returns the button if the command string is used by the async usercmd generator.
  904. ================
  905. */
  906. int idUsercmdGenLocal::CommandStringUsercmdData( const char *cmdString ) {
  907. for ( userCmdString_t *ucs = userCmdStrings ; ucs->string ; ucs++ ) {
  908. if ( idStr::Icmp( cmdString, ucs->string ) == 0 ) {
  909. return ucs->button;
  910. }
  911. }
  912. return UB_NONE;
  913. }
  914. /*
  915. ================
  916. idUsercmdGenLocal::Init
  917. ================
  918. */
  919. void idUsercmdGenLocal::Init( void ) {
  920. initialized = true;
  921. }
  922. /*
  923. ================
  924. idUsercmdGenLocal::InitForNewMap
  925. ================
  926. */
  927. void idUsercmdGenLocal::InitForNewMap( void ) {
  928. flags = 0;
  929. impulse = 0;
  930. toggled_crouch.Clear();
  931. toggled_run.Clear();
  932. toggled_zoom.Clear();
  933. toggled_run.on = in_alwaysRun.GetBool();
  934. Clear();
  935. ClearAngles();
  936. }
  937. /*
  938. ================
  939. idUsercmdGenLocal::Shutdown
  940. ================
  941. */
  942. void idUsercmdGenLocal::Shutdown( void ) {
  943. initialized = false;
  944. }
  945. /*
  946. ================
  947. idUsercmdGenLocal::Clear
  948. ================
  949. */
  950. void idUsercmdGenLocal::Clear( void ) {
  951. // clears all key states
  952. memset( buttonState, 0, sizeof( buttonState ) );
  953. memset( keyState, false, sizeof( keyState ) );
  954. memset( joystickAxis, 0, sizeof( joystickAxis ) );
  955. inhibitCommands = false;
  956. mouseDx = mouseDy = 0;
  957. mouseButton = 0;
  958. mouseDown = false;
  959. }
  960. /*
  961. ================
  962. idUsercmdGenLocal::ClearAngles
  963. ================
  964. */
  965. void idUsercmdGenLocal::ClearAngles( void ) {
  966. viewangles.Zero();
  967. }
  968. /*
  969. ================
  970. idUsercmdGenLocal::TicCmd
  971. Returns a buffered usercmd
  972. ================
  973. */
  974. usercmd_t idUsercmdGenLocal::TicCmd( int ticNumber ) {
  975. // the packetClient code can legally ask for com_ticNumber+1, because
  976. // it is in the async code and com_ticNumber hasn't been updated yet,
  977. // but all other code should never ask for anything > com_ticNumber
  978. if ( ticNumber > com_ticNumber+1 ) {
  979. common->Error( "idUsercmdGenLocal::TicCmd ticNumber > com_ticNumber" );
  980. }
  981. if ( ticNumber <= com_ticNumber - MAX_BUFFERED_USERCMD ) {
  982. // this can happen when something in the game code hitches badly, allowing the
  983. // async code to overflow the buffers
  984. //common->Printf( "warning: idUsercmdGenLocal::TicCmd ticNumber <= com_ticNumber - MAX_BUFFERED_USERCMD\n" );
  985. }
  986. return buffered[ ticNumber & (MAX_BUFFERED_USERCMD-1) ];
  987. }
  988. //======================================================================
  989. /*
  990. ===================
  991. idUsercmdGenLocal::Key
  992. Handles async mouse/keyboard button actions
  993. ===================
  994. */
  995. void idUsercmdGenLocal::Key( int keyNum, bool down ) {
  996. // Sanity check, sometimes we get double message :(
  997. if ( keyState[ keyNum ] == down ) {
  998. return;
  999. }
  1000. keyState[ keyNum ] = down;
  1001. int action = idKeyInput::GetUsercmdAction( keyNum );
  1002. if ( down ) {
  1003. buttonState[ action ]++;
  1004. if ( !Inhibited() ) {
  1005. if ( action >= UB_IMPULSE0 && action <= UB_IMPULSE61 ) {
  1006. cmd.impulse = action - UB_IMPULSE0;
  1007. cmd.flags ^= UCF_IMPULSE_SEQUENCE;
  1008. }
  1009. }
  1010. } else {
  1011. buttonState[ action ]--;
  1012. // we might have one held down across an app active transition
  1013. if ( buttonState[ action ] < 0 ) {
  1014. buttonState[ action ] = 0;
  1015. }
  1016. }
  1017. }
  1018. /*
  1019. ===================
  1020. idUsercmdGenLocal::Mouse
  1021. ===================
  1022. */
  1023. void idUsercmdGenLocal::Mouse( void ) {
  1024. int i, numEvents;
  1025. numEvents = Sys_PollMouseInputEvents();
  1026. if ( numEvents ) {
  1027. //
  1028. // Study each of the buffer elements and process them.
  1029. //
  1030. for( i = 0; i < numEvents; i++ ) {
  1031. int action, value;
  1032. if ( Sys_ReturnMouseInputEvent( i, action, value ) ) {
  1033. if ( action >= M_ACTION1 && action <= M_ACTION8 ) {
  1034. mouseButton = K_MOUSE1 + ( action - M_ACTION1 );
  1035. mouseDown = ( value != 0 );
  1036. Key( mouseButton, mouseDown );
  1037. } else {
  1038. switch ( action ) {
  1039. case M_DELTAX:
  1040. mouseDx += value;
  1041. continuousMouseX += value;
  1042. break;
  1043. case M_DELTAY:
  1044. mouseDy += value;
  1045. continuousMouseY += value;
  1046. break;
  1047. case M_DELTAZ:
  1048. int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP;
  1049. value = abs( value );
  1050. while( value-- > 0 ) {
  1051. Key( key, true );
  1052. Key( key, false );
  1053. mouseButton = key;
  1054. mouseDown = true;
  1055. }
  1056. break;
  1057. }
  1058. }
  1059. }
  1060. }
  1061. }
  1062. Sys_EndMouseInputEvents();
  1063. }
  1064. /*
  1065. ===============
  1066. idUsercmdGenLocal::Keyboard
  1067. ===============
  1068. */
  1069. void idUsercmdGenLocal::Keyboard( void ) {
  1070. int numEvents = Sys_PollKeyboardInputEvents();
  1071. if ( numEvents ) {
  1072. //
  1073. // Study each of the buffer elements and process them.
  1074. //
  1075. int key;
  1076. bool state;
  1077. for( int i = 0; i < numEvents; i++ ) {
  1078. if (Sys_ReturnKeyboardInputEvent( i, key, state )) {
  1079. Key ( key, state );
  1080. }
  1081. }
  1082. }
  1083. Sys_EndKeyboardInputEvents();
  1084. }
  1085. /*
  1086. ===============
  1087. idUsercmdGenLocal::Joystick
  1088. ===============
  1089. */
  1090. void idUsercmdGenLocal::Joystick( void ) {
  1091. int numEvents = Sys_PollJoystickInputEvents( 0 );
  1092. // Study each of the buffer elements and process them.
  1093. for ( int i = 0; i < numEvents; i++ ) {
  1094. int action;
  1095. int value;
  1096. if ( Sys_ReturnJoystickInputEvent( i, action, value ) ) {
  1097. if ( action >= J_ACTION1 && action <= J_ACTION_MAX ) {
  1098. int joyButton = K_JOY1 + ( action - J_ACTION1 );
  1099. Key( joyButton, ( value != 0 ) );
  1100. } else if ( ( action >= J_AXIS_MIN ) && ( action <= J_AXIS_MAX ) ) {
  1101. joystickAxis[ action - J_AXIS_MIN ] = static_cast<float>( value ) / 32767.0f;
  1102. } else if ( action >= J_DPAD_UP && action <= J_DPAD_RIGHT ) {
  1103. int joyButton = K_JOY_DPAD_UP + ( action - J_DPAD_UP );
  1104. Key( joyButton, ( value != 0 ) );
  1105. } else {
  1106. //assert( !"Unknown joystick event" );
  1107. }
  1108. }
  1109. }
  1110. Sys_EndJoystickInputEvents();
  1111. }
  1112. /*
  1113. ================
  1114. idUsercmdGenLocal::UsercmdInterrupt
  1115. Called asyncronously
  1116. ================
  1117. */
  1118. void idUsercmdGenLocal::UsercmdInterrupt( void ) {
  1119. // dedicated servers won't create usercmds
  1120. if ( !initialized ) {
  1121. return;
  1122. }
  1123. // init the usercmd for com_ticNumber+1
  1124. InitCurrent();
  1125. // process the system mouse events
  1126. Mouse();
  1127. // process the system keyboard events
  1128. Keyboard();
  1129. // process the system joystick events
  1130. if ( in_useJoystick.GetBool() ) {
  1131. Joystick();
  1132. }
  1133. // create the usercmd for com_ticNumber+1
  1134. MakeCurrent();
  1135. // save a number for debugging cmdDemos and networking
  1136. cmd.sequence = com_ticNumber+1;
  1137. buffered[(com_ticNumber+1) & (MAX_BUFFERED_USERCMD-1)] = cmd;
  1138. }
  1139. /*
  1140. ================
  1141. idUsercmdGenLocal::MouseState
  1142. ================
  1143. */
  1144. void idUsercmdGenLocal::MouseState( int *x, int *y, int *button, bool *down ) {
  1145. *x = continuousMouseX;
  1146. *y = continuousMouseY;
  1147. *button = mouseButton;
  1148. *down = mouseDown;
  1149. }
  1150. /*
  1151. ================
  1152. idUsercmdGenLocal::GetDirectUsercmd
  1153. ================
  1154. */
  1155. usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
  1156. pollTime = Sys_Milliseconds();
  1157. if ( pollTime - lastPollTime > 100 ) {
  1158. lastPollTime = pollTime - 100;
  1159. }
  1160. // initialize current usercmd
  1161. InitCurrent();
  1162. // process the system mouse events
  1163. Mouse();
  1164. // process the system keyboard events
  1165. Keyboard();
  1166. // process the system joystick events
  1167. if ( in_useJoystick.GetBool() ) {
  1168. Joystick();
  1169. }
  1170. // create the usercmd
  1171. MakeCurrent();
  1172. cmd.duplicateCount = 0;
  1173. lastPollTime = pollTime;
  1174. return cmd;
  1175. }