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