Paranoia2/cl_dll/input.cpp

1051 lines
23 KiB
C++

//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
// cl.input.c -- builds an intended movement command to send to the server
//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
// rights reserved.
#include "hud.h"
#include "cl_util.h"
#include "camera.h"
#include "kbutton.h"
#include "cvardef.h"
#include "usercmd.h"
#include "const.h"
#include "camera.h"
#include "in_defs.h"
#include <string.h>
#include <mathlib.h>
#include <ctype.h>
#include "vgui_TeamFortressViewport.h"
extern "C"
{
struct kbutton_s DLLEXPORT *KB_Find( const char *name );
void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active );
int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding );
}
extern int g_iAlive;
extern int g_weaponselect;
extern cl_enginefunc_t gEngfuncs;
void IN_Init (void);
void IN_Move ( float frametime, usercmd_t *cmd);
void IN_Shutdown( void );
void V_Init( void );
void VectorAngles( const float *forward, float *angles );
int CL_ButtonBits( int );
// xxx need client dll function to get and clear impuse
extern cvar_t *in_joystick;
int in_impulse = 0;
int in_cancel = 0;
cvar_t *m_pitch;
cvar_t *m_yaw;
cvar_t *m_forward;
cvar_t *m_side;
cvar_t *lookstrafe;
cvar_t *lookspring;
cvar_t *cl_pitchup;
cvar_t *cl_pitchdown;
cvar_t *cl_upspeed;
cvar_t *cl_forwardspeed;
cvar_t *cl_backspeed;
cvar_t *cl_sidespeed;
cvar_t *cl_movespeedkey;
cvar_t *cl_yawspeed;
cvar_t *cl_pitchspeed;
cvar_t *cl_anglespeedkey;
cvar_t *cl_vsmoothing;
/*
===============================================================================
KEY BUTTONS
Continuous button event tracking is complicated by the fact that two different
input sources (say, mouse button 1 and the control key) can both press the
same button, but the button should only be released when both of the
pressing key have been released.
When a key event issues a button command (+forward, +attack, etc), it appends
its key number as a parameter to the command so it can be matched up with
the release.
state bit 0 is the current state of the key
state bit 1 is edge triggered on the up to down transition
state bit 2 is edge triggered on the down to up transition
===============================================================================
*/
kbutton_t in_mlook;
kbutton_t in_klook;
kbutton_t in_jlook;
kbutton_t in_left;
kbutton_t in_right;
kbutton_t in_forward;
kbutton_t in_back;
kbutton_t in_lookup;
kbutton_t in_lookdown;
kbutton_t in_moveleft;
kbutton_t in_moveright;
kbutton_t in_strafe;
kbutton_t in_speed;
kbutton_t in_use;
kbutton_t in_jump;
kbutton_t in_attack;
kbutton_t in_attack2;
kbutton_t in_up;
kbutton_t in_down;
kbutton_t in_duck;
kbutton_t in_reload;
kbutton_t in_alt1;
kbutton_t in_score;
kbutton_t in_break;
kbutton_t in_graph; // Display the netgraph
kbutton_t in_sprint;
typedef struct kblist_s
{
struct kblist_s *next;
kbutton_t *pkey;
char name[32];
} kblist_t;
kblist_t *g_kbkeys = NULL;
/*
============
KB_ConvertString
Removes references to +use and replaces them with the keyname in the output string. If
a binding is unfound, then the original text is retained.
NOTE: Only works for text with +word in it.
============
*/
int KB_ConvertString( char *in, char **ppout )
{
char sz[ 4096 ];
char binding[ 64 ];
char *p;
char *pOut;
char *pEnd;
const char *pBinding;
if ( !ppout )
return 0;
*ppout = NULL;
p = in;
pOut = sz;
while ( *p )
{
if ( *p == '+' )
{
pEnd = binding;
while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) )
{
*pEnd++ = *p++;
}
*pEnd = '\0';
pBinding = NULL;
if ( strlen( binding + 1 ) > 0 )
{
// See if there is a binding for binding?
pBinding = gEngfuncs.Key_LookupBinding( binding + 1 );
}
if ( pBinding )
{
*pOut++ = '[';
pEnd = (char *)pBinding;
}
else
{
pEnd = binding;
}
while ( *pEnd )
{
*pOut++ = *pEnd++;
}
if ( pBinding )
{
*pOut++ = ']';
}
}
else
{
*pOut++ = *p++;
}
}
*pOut = '\0';
pOut = ( char * )malloc( strlen( sz ) + 1 );
strcpy( pOut, sz );
*ppout = pOut;
return 1;
}
/*
============
KB_Find
Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files
============
*/
struct kbutton_s DLLEXPORT *KB_Find( const char *name )
{
kblist_t *p;
p = g_kbkeys;
while ( p )
{
if ( !stricmp( name, p->name ) )
return p->pkey;
p = p->next;
}
return NULL;
}
/*
============
KB_Add
Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find
============
*/
void KB_Add( const char *name, kbutton_t *pkb )
{
kblist_t *p;
kbutton_t *kb;
kb = KB_Find( name );
if ( kb )
return;
p = ( kblist_t * )malloc( sizeof( kblist_t ) );
memset( p, 0, sizeof( *p ) );
strcpy( p->name, name );
p->pkey = pkb;
p->next = g_kbkeys;
g_kbkeys = p;
}
/*
============
KB_Init
Add kbutton_t definitions that the engine can query if needed
============
*/
void KB_Init( void )
{
g_kbkeys = NULL;
KB_Add( "in_graph", &in_graph );
KB_Add( "in_mlook", &in_mlook );
KB_Add( "in_jlook", &in_jlook );
}
/*
============
KB_Shutdown
Clear kblist
============
*/
void KB_Shutdown( void )
{
kblist_t *p, *n;
p = g_kbkeys;
while ( p )
{
n = p->next;
free( p );
p = n;
}
g_kbkeys = NULL;
}
/*
============
KeyDown
============
*/
void KeyDown (kbutton_t *b)
{
int k;
char *c;
c = gEngfuncs.Cmd_Argv(1);
if (c[0])
k = atoi(c);
else
k = -1; // typed manually at the console for continuous down
if (k == b->down[0] || k == b->down[1])
return; // repeating key
if (!b->down[0])
b->down[0] = k;
else if (!b->down[1])
b->down[1] = k;
else
{
gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c);
return;
}
if (b->state & 1)
return; // still down
b->state |= 1 + 2; // down + impulse down
}
/*
============
KeyUp
============
*/
void KeyUp (kbutton_t *b)
{
int k;
char *c;
c = gEngfuncs.Cmd_Argv(1);
if (c[0])
k = atoi(c);
else
{ // typed manually at the console, assume for unsticking, so clear all
b->down[0] = b->down[1] = 0;
b->state = 4; // impulse up
return;
}
if (b->down[0] == k)
b->down[0] = 0;
else if (b->down[1] == k)
b->down[1] = 0;
else
return; // key up without coresponding down (menu pass through)
if (b->down[0] || b->down[1])
{
//Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c);
return; // some other key is still holding it down
}
if (!(b->state & 1))
return; // still up (this should not happen)
b->state &= ~1; // now up
b->state |= 4; // impulse up
}
/*
============
HUD_Key_Event
Return 1 to allow engine to process the key, otherwise, act on it as needed
============
*/
int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding )
{
if (gViewPort)
return gViewPort->KeyInput(down, keynum, pszCurrentBinding);
return 1;
}
void IN_BreakDown( void ) { KeyDown( &in_break );};
void IN_BreakUp( void ) { KeyUp( &in_break ); };
void IN_KLookDown (void) {KeyDown(&in_klook);}
void IN_KLookUp (void) {KeyUp(&in_klook);}
void IN_JLookDown (void) {KeyDown(&in_jlook);}
void IN_JLookUp (void) {KeyUp(&in_jlook);}
void IN_MLookDown (void) {KeyDown(&in_mlook);}
void IN_UpDown(void) {KeyDown(&in_up);}
void IN_UpUp(void) {KeyUp(&in_up);}
void IN_DownDown(void) {KeyDown(&in_down);}
void IN_DownUp(void) {KeyUp(&in_down);}
void IN_LeftDown(void) {KeyDown(&in_left);}
void IN_LeftUp(void) {KeyUp(&in_left);}
void IN_RightDown(void) {KeyDown(&in_right);}
void IN_RightUp(void) {KeyUp(&in_right);}
void IN_ForwardDown(void)
{
KeyDown(&in_forward);
gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD );
}
void IN_ForwardUp(void)
{
KeyUp(&in_forward);
gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD );
}
void IN_BackDown(void)
{
KeyDown(&in_back);
gHUD.m_Spectator.HandleButtonsDown( IN_BACK );
}
void IN_BackUp(void)
{
KeyUp(&in_back);
gHUD.m_Spectator.HandleButtonsUp( IN_BACK );
}
void IN_LookupDown(void) {KeyDown(&in_lookup);}
void IN_LookupUp(void) {KeyUp(&in_lookup);}
void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
void IN_MoveleftDown(void)
{
KeyDown(&in_moveleft);
gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT );
}
void IN_MoveleftUp(void)
{
KeyUp(&in_moveleft);
gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT );
}
void IN_MoverightDown(void)
{
KeyDown(&in_moveright);
gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT );
}
void IN_MoverightUp(void)
{
KeyUp(&in_moveright);
gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT );
}
void IN_SpeedDown(void) {KeyDown(&in_speed);}
void IN_SpeedUp(void) {KeyUp(&in_speed);}
void IN_SprintDown(void) {KeyDown(&in_sprint);}
void IN_SprintUp(void) {KeyUp(&in_sprint);}
void IN_StrafeDown(void) {KeyDown(&in_strafe);}
void IN_StrafeUp(void) {KeyUp(&in_strafe);}
// needs capture by hud/vgui also
extern void __CmdFunc_InputPlayerSpecial(void);
void IN_Attack2Down(void)
{
KeyDown(&in_attack2);
gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 );
}
void IN_Attack2Up(void) {KeyUp(&in_attack2);}
void IN_UseDown (void)
{
KeyDown(&in_use);
gHUD.m_Spectator.HandleButtonsDown( IN_USE );
}
void IN_UseUp (void) {KeyUp(&in_use);}
void IN_JumpDown (void)
{
KeyDown(&in_jump);
gHUD.m_Spectator.HandleButtonsDown( IN_JUMP );
}
void IN_JumpUp (void) {KeyUp(&in_jump);}
void IN_DuckDown(void)
{
KeyDown(&in_duck);
gHUD.m_Spectator.HandleButtonsDown( IN_DUCK );
}
void IN_DuckUp(void) {KeyUp(&in_duck);}
void IN_ReloadDown(void) {KeyDown(&in_reload);}
void IN_ReloadUp(void) {KeyUp(&in_reload);}
void IN_Alt1Down(void) {KeyDown(&in_alt1);}
void IN_Alt1Up(void) {KeyUp(&in_alt1);}
void IN_GraphDown(void) {KeyDown(&in_graph);}
void IN_GraphUp(void) {KeyUp(&in_graph);}
void IN_AttackDown(void)
{
KeyDown( &in_attack );
gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK );
}
void IN_AttackUp(void)
{
KeyUp( &in_attack );
in_cancel = 0;
}
// Special handling
void IN_Cancel(void)
{
in_cancel = 1;
}
void IN_Impulse (void)
{
in_impulse = atoi( gEngfuncs.Cmd_Argv(1) );
}
void IN_ScoreDown(void)
{
KeyDown(&in_score);
if ( gViewPort )
{
gViewPort->ShowScoreBoard();
}
}
void IN_ScoreUp(void)
{
KeyUp(&in_score);
if ( gViewPort )
{
gViewPort->HideScoreBoard();
}
}
void IN_MLookUp (void)
{
KeyUp( &in_mlook );
if ( !( in_mlook.state & 1 ) && lookspring->value )
{
V_StartPitchDrift();
}
}
/*
===============
CL_KeyState
Returns 0.25 if a key was pressed and released during the frame,
0.5 if it was pressed and held
0 if held then released, and
1.0 if held for the entire time
===============
*/
float CL_KeyState (kbutton_t *key)
{
float val = 0.0;
int impulsedown, impulseup, down;
impulsedown = key->state & 2;
impulseup = key->state & 4;
down = key->state & 1;
if ( impulsedown && !impulseup )
{
// pressed and held this frame?
val = down ? 0.5 : 0.0;
}
if ( impulseup && !impulsedown )
{
// released this frame?
val = down ? 0.0 : 0.0;
}
if ( !impulsedown && !impulseup )
{
// held the entire frame?
val = down ? 1.0 : 0.0;
}
if ( impulsedown && impulseup )
{
if ( down )
{
// released and re-pressed this frame
val = 0.75;
}
else
{
// pressed and released this frame
val = 0.25;
}
}
// clear impulses
key->state &= 1;
return val;
}
/*
================
CL_AdjustAngles
Moves the local angle positions
================
*/
void CL_AdjustAngles ( float frametime, float *viewangles )
{
float speed;
float up, down;
if (in_speed.state & 1)
{
speed = frametime * cl_anglespeedkey->value;
}
else
{
speed = frametime;
}
if (!(in_strafe.state & 1))
{
viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
viewangles[YAW] = anglemod(viewangles[YAW]);
}
if (in_klook.state & 1)
{
V_StopPitchDrift ();
viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
}
up = CL_KeyState (&in_lookup);
down = CL_KeyState(&in_lookdown);
viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
viewangles[PITCH] += speed*cl_pitchspeed->value * down;
if (up || down)
V_StopPitchDrift ();
if (viewangles[PITCH] > cl_pitchdown->value)
viewangles[PITCH] = cl_pitchdown->value;
if (viewangles[PITCH] < -cl_pitchup->value)
viewangles[PITCH] = -cl_pitchup->value;
if (viewangles[ROLL] > 50)
viewangles[ROLL] = 50;
if (viewangles[ROLL] < -50)
viewangles[ROLL] = -50;
}
/*
================
CL_CreateMove
Send the intended movement message to the server
if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and
2 ) we have finished signing on to server
================
*/
void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active )
{
vec3_t viewangles;
static vec3_t oldangles;
if ( active )
{
//memset( viewangles, 0, sizeof( vec3_t ) );
//viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0;
gEngfuncs.GetViewAngles( (float *)viewangles );
CL_AdjustAngles ( frametime, viewangles );
memset (cmd, 0, sizeof(*cmd));
gEngfuncs.SetViewAngles( (float *)viewangles );
if ( in_strafe.state & 1 )
{
cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
}
cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
if ( !(in_klook.state & 1 ) )
{
cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back);
}
// adjust for speed key
if ( in_speed.state & 1 )
{
cmd->forwardmove *= cl_movespeedkey->value;
cmd->sidemove *= cl_movespeedkey->value;
cmd->upmove *= cl_movespeedkey->value;
}
// clip to maxspeed
// buz: little fix - dont need to do it here, pm code will handle it
/* float spd = gEngfuncs.GetClientMaxspeed();
if ( spd != 0.0 )
{
// scale the 3 speeds so that the total velocity is not > cl.maxspeed
float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) );
if ( fmov > spd )
{
float fratio = spd / fmov;
cmd->forwardmove *= fratio;
cmd->sidemove *= fratio;
cmd->upmove *= fratio;
}
}*/
// Allow mice and other controllers to add their inputs
IN_Move ( frametime, cmd );
}
cmd->impulse = in_impulse;
in_impulse = 0;
cmd->weaponselect = g_weaponselect;
g_weaponselect = 0;
//
// set button and flag bits
//
cmd->buttons = CL_ButtonBits( 1 );
// If they're in a modal dialog, ignore the attack button.
if(GetClientVoiceMgr()->IsInSquelchMode())
cmd->buttons &= ~IN_ATTACK;
// Using joystick?
if ( in_joystick->value )
{
if ( cmd->forwardmove > 0 )
{
cmd->buttons |= IN_FORWARD;
}
else if ( cmd->forwardmove < 0 )
{
cmd->buttons |= IN_BACK;
}
}
gEngfuncs.GetViewAngles( (float *)viewangles );
// Set current view angles.
// buz: in spec tank mode check for bounds
// gEngfuncs.Con_Printf("pitch: %f, yaw: %f\n", viewangles[PITCH], viewangles[YAW]);
if (gHUD.m_SpecTank_on)
{
// check yaw
float ofs = viewangles[YAW] - gHUD.m_SpecTank_defYaw;
if (ofs > 180) ofs -= 360;
else if (ofs < -180) ofs += 360;
if (ofs < -gHUD.m_SpecTank_coneHor)
viewangles[YAW] = gHUD.m_SpecTank_defYaw - gHUD.m_SpecTank_coneHor;
else if (ofs > gHUD.m_SpecTank_coneHor)
viewangles[YAW] = gHUD.m_SpecTank_defYaw + gHUD.m_SpecTank_coneHor;
// check pitch
if (viewangles[PITCH] > gHUD.m_SpecTank_coneVer)
viewangles[PITCH] = gHUD.m_SpecTank_coneVer;
else if (viewangles[PITCH] < -gHUD.m_SpecTank_coneVer)
viewangles[PITCH] = -gHUD.m_SpecTank_coneVer;
// всем спасибо, все свободны
gEngfuncs.SetViewAngles( (float *)viewangles );
}
if ( g_iAlive )
{
VectorCopy( viewangles, cmd->viewangles );
VectorCopy( viewangles, oldangles );
}
else
{
VectorCopy( oldangles, cmd->viewangles );
}
}
/*
============
CL_IsDead
Returns 1 if health is <= 0
============
*/
int CL_IsDead( void )
{
return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0;
}
/*
============
CL_ButtonBits
Returns appropriate button info for keyboard and mouse state
Set bResetState to 1 to clear old state info
============
*/
int CL_ButtonBits( int bResetState )
{
int bits = 0;
if ( in_attack.state & 3 )
{
bits |= IN_ATTACK;
}
if (in_duck.state & 3)
{
bits |= IN_DUCK;
}
if (in_jump.state & 3)
{
bits |= IN_JUMP;
}
if ( in_forward.state & 3 )
{
bits |= IN_FORWARD;
}
if (in_back.state & 3)
{
bits |= IN_BACK;
}
if (in_use.state & 3)
{
bits |= IN_USE;
}
if (in_cancel)
{
bits |= IN_CANCEL;
}
if ( in_left.state & 3 )
{
bits |= IN_LEFT;
}
if (in_right.state & 3)
{
bits |= IN_RIGHT;
}
if ( in_moveleft.state & 3 )
{
bits |= IN_MOVELEFT;
}
if (in_moveright.state & 3)
{
bits |= IN_MOVERIGHT;
}
if (in_attack2.state & 3)
{
bits |= IN_ATTACK2;
}
if (in_reload.state & 3)
{
bits |= IN_RELOAD;
}
if (in_alt1.state & 3)
{
bits |= IN_ALT1;
}
if ( in_score.state & 3 )
{
bits |= IN_SCORE;
}
if ( in_sprint.state & 3 )
{
bits |= IN_RUN;
}
// Dead or in intermission? Shore scoreboard, too
if ( CL_IsDead() || gHUD.m_iIntermission )
{
bits |= IN_SCORE;
}
if ( bResetState )
{
in_attack.state &= ~2;
in_duck.state &= ~2;
in_jump.state &= ~2;
in_forward.state &= ~2;
in_back.state &= ~2;
in_use.state &= ~2;
in_left.state &= ~2;
in_right.state &= ~2;
in_moveleft.state &= ~2;
in_moveright.state &= ~2;
in_attack2.state &= ~2;
in_reload.state &= ~2;
in_alt1.state &= ~2;
in_score.state &= ~2;
in_sprint.state &= ~2;
}
return bits;
}
/*
============
CL_ResetButtonBits
============
*/
void CL_ResetButtonBits( int bits )
{
int bitsNew = CL_ButtonBits( 0 ) ^ bits;
// Has the attack button been changed
if ( bitsNew & IN_ATTACK )
{
// Was it pressed? or let go?
if ( bits & IN_ATTACK )
{
KeyDown( &in_attack );
}
else
{
// totally clear state
in_attack.state &= ~7;
}
}
}
/*
============
InitInput
============
*/
void InitInput (void)
{
gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown);
gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp);
gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown);
gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp);
gEngfuncs.pfnAddCommand ("+left",IN_LeftDown);
gEngfuncs.pfnAddCommand ("-left",IN_LeftUp);
gEngfuncs.pfnAddCommand ("+right",IN_RightDown);
gEngfuncs.pfnAddCommand ("-right",IN_RightUp);
gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown);
gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp);
gEngfuncs.pfnAddCommand ("+back",IN_BackDown);
gEngfuncs.pfnAddCommand ("-back",IN_BackUp);
gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown);
gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp);
gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown);
gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp);
gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown);
gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp);
gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown);
gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp);
gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown);
gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp);
gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown);
gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp);
gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown);
gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp);
gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down);
gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up);
gEngfuncs.pfnAddCommand ("+use", IN_UseDown);
gEngfuncs.pfnAddCommand ("-use", IN_UseUp);
gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown);
gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp);
gEngfuncs.pfnAddCommand ("impulse", IN_Impulse);
gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown);
gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp);
gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown);
gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp);
gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown);
gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp);
gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown);
gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp);
gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown);
gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp);
gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down);
gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up);
gEngfuncs.pfnAddCommand ("+score", IN_ScoreDown);
gEngfuncs.pfnAddCommand ("-score", IN_ScoreUp);
gEngfuncs.pfnAddCommand ("-sprint", IN_SprintUp);
gEngfuncs.pfnAddCommand ("+sprint", IN_SprintDown);
gEngfuncs.pfnAddCommand ("+showscores", IN_ScoreDown);
gEngfuncs.pfnAddCommand ("-showscores", IN_ScoreUp);
gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown);
gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp);
gEngfuncs.pfnAddCommand ("+break",IN_BreakDown);
gEngfuncs.pfnAddCommand ("-break",IN_BreakUp);
lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE );
lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE );
cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 );
cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 );
cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 );
cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", FCVAR_ARCHIVE );
cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE );
cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE );
cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", FCVAR_ARCHIVE );
cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 );
cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 );
cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 );
cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE );
m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE );
m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE );
m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE );
m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE );
// Initialize third person camera controls.
CAM_Init();
// Initialize inputs
IN_Init();
// Initialize keyboard
KB_Init();
// Initialize view system
V_Init();
}
/*
============
ShutdownInput
============
*/
void ShutdownInput( void )
{
IN_Shutdown();
KB_Shutdown();
}