2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2011-04-15 00:58:39 +00:00
# include <base/tl/sorted_array.h>
2010-05-29 07:25:38 +00:00
# include <base/math.h>
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
# include <engine/shared/config.h>
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
# include <game/collision.h>
# include <game/client/gameclient.h>
# include <game/client/component.h>
# include <game/client/components/chat.h>
# include <game/client/components/menus.h>
2011-03-01 17:31:20 +00:00
# include <game/client/components/scoreboard.h>
2010-05-29 07:25:38 +00:00
# include "controls.h"
CControls : : CControls ( )
2008-08-27 15:48:50 +00:00
{
2010-05-31 21:40:40 +00:00
mem_zero ( & m_LastData , sizeof ( m_LastData ) ) ;
}
void CControls : : OnReset ( )
{
m_LastData . m_Direction = 0 ;
m_LastData . m_Hook = 0 ;
2010-06-02 17:39:28 +00:00
// simulate releasing the fire button
if ( ( m_LastData . m_Fire & 1 ) ! = 0 )
m_LastData . m_Fire + + ;
m_LastData . m_Fire & = INPUT_STATE_MASK ;
2010-05-31 21:40:40 +00:00
m_LastData . m_Jump = 0 ;
m_InputData = m_LastData ;
2011-04-13 18:37:12 +00:00
2010-05-31 21:40:40 +00:00
m_InputDirectionLeft = 0 ;
m_InputDirectionRight = 0 ;
2008-08-27 15:48:50 +00:00
}
2011-01-17 11:28:37 +00:00
void CControls : : OnRelease ( )
{
2011-02-16 10:59:30 +00:00
//OnReset();
2011-01-17 11:28:37 +00:00
}
2010-08-10 11:54:13 +00:00
void CControls : : OnPlayerDeath ( )
{
m_LastData . m_WantedWeapon = m_InputData . m_WantedWeapon = 0 ;
}
2010-08-25 20:30:21 +00:00
static void ConKeyInputState ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
( ( int * ) pUserData ) [ 0 ] = pResult - > GetInteger ( 0 ) ;
2008-08-27 15:48:50 +00:00
}
2010-08-25 20:30:21 +00:00
static void ConKeyInputCounter ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
int * v = ( int * ) pUserData ;
if ( ( ( * v ) & 1 ) ! = pResult - > GetInteger ( 0 ) )
2008-08-27 15:48:50 +00:00
( * v ) + + ;
* v & = INPUT_STATE_MASK ;
}
2008-08-27 20:04:07 +00:00
2010-05-29 07:25:38 +00:00
struct CInputSet
2008-08-27 20:04:07 +00:00
{
2010-05-29 07:25:38 +00:00
CControls * m_pControls ;
int * m_pVariable ;
int m_Value ;
2008-08-27 20:04:07 +00:00
} ;
2010-08-25 20:30:21 +00:00
static void ConKeyInputSet ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CInputSet * pSet = ( CInputSet * ) pUserData ;
if ( pResult - > GetInteger ( 0 ) )
* pSet - > m_pVariable = pSet - > m_Value ;
2008-08-27 15:48:50 +00:00
}
2010-08-25 20:30:21 +00:00
static void ConKeyInputNextPrevWeapon ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CInputSet * pSet = ( CInputSet * ) pUserData ;
2010-08-25 20:30:21 +00:00
ConKeyInputCounter ( pResult , pSet - > m_pVariable , ClientID ) ;
2010-05-29 07:25:38 +00:00
pSet - > m_pControls - > m_InputData . m_WantedWeapon = 0 ;
2008-08-27 20:04:07 +00:00
}
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
void CControls : : OnConsoleInit ( )
2008-08-27 15:48:50 +00:00
{
// game commands
2011-03-16 14:27:30 +00:00
Console ( ) - > Register ( " +left " , " " , CFGFLAG_CLIENT , ConKeyInputState , & m_InputDirectionLeft , " Move left " , IConsole : : CONSOLELEVEL_USER ) ;
Console ( ) - > Register ( " +right " , " " , CFGFLAG_CLIENT , ConKeyInputState , & m_InputDirectionRight , " Move right " , IConsole : : CONSOLELEVEL_USER ) ;
Console ( ) - > Register ( " +jump " , " " , CFGFLAG_CLIENT , ConKeyInputState , & m_InputData . m_Jump , " Jump " , IConsole : : CONSOLELEVEL_USER ) ;
Console ( ) - > Register ( " +hook " , " " , CFGFLAG_CLIENT , ConKeyInputState , & m_InputData . m_Hook , " Hook " , IConsole : : CONSOLELEVEL_USER ) ;
Console ( ) - > Register ( " +fire " , " " , CFGFLAG_CLIENT , ConKeyInputCounter , & m_InputData . m_Fire , " Fire " , IConsole : : CONSOLELEVEL_USER ) ;
2011-04-13 23:27:49 +00:00
{ static CInputSet s_Set = { this , & m_InputData . m_WantedWeapon , 1 } ; Console ( ) - > Register ( " +weapon1 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to hammer " , IConsole : : CONSOLELEVEL_USER ) ; }
{ static CInputSet s_Set = { this , & m_InputData . m_WantedWeapon , 2 } ; Console ( ) - > Register ( " +weapon2 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to gun " , IConsole : : CONSOLELEVEL_USER ) ; }
{ static CInputSet s_Set = { this , & m_InputData . m_WantedWeapon , 3 } ; Console ( ) - > Register ( " +weapon3 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to shotgun " , IConsole : : CONSOLELEVEL_USER ) ; }
{ static CInputSet s_Set = { this , & m_InputData . m_WantedWeapon , 4 } ; Console ( ) - > Register ( " +weapon4 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to grenade " , IConsole : : CONSOLELEVEL_USER ) ; }
{ static CInputSet s_Set = { this , & m_InputData . m_WantedWeapon , 5 } ; Console ( ) - > Register ( " +weapon5 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to rifle " , IConsole : : CONSOLELEVEL_USER ) ; }
2011-03-16 14:27:30 +00:00
2011-04-13 23:27:49 +00:00
{ static CInputSet s_Set = { this , & m_InputData . m_NextWeapon , 0 } ; Console ( ) - > Register ( " +nextweapon " , " " , CFGFLAG_CLIENT , ConKeyInputNextPrevWeapon , ( void * ) & s_Set , " Switch to next weapon " , IConsole : : CONSOLELEVEL_USER ) ; }
{ static CInputSet s_Set = { this , & m_InputData . m_PrevWeapon , 0 } ; Console ( ) - > Register ( " +prevweapon " , " " , CFGFLAG_CLIENT , ConKeyInputNextPrevWeapon , ( void * ) & s_Set , " Switch to previous weapon " , IConsole : : CONSOLELEVEL_USER ) ; }
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CControls : : OnMessage ( int Msg , void * pRawMsg )
2008-08-31 21:50:14 +00:00
{
2011-04-13 18:37:12 +00:00
if ( Msg = = NETMSGTYPE_SV_WEAPONPICKUP )
{
CNetMsg_Sv_WeaponPickup * pMsg = ( CNetMsg_Sv_WeaponPickup * ) pRawMsg ;
if ( g_Config . m_ClAutoswitchWeapons )
m_InputData . m_WantedWeapon = pMsg - > m_Weapon + 1 ;
}
2008-08-31 21:50:14 +00:00
}
2010-05-29 07:25:38 +00:00
int CControls : : SnapInput ( int * pData )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
static int64 LastSendTime = 0 ;
bool Send = false ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// update player state
2010-05-29 07:25:38 +00:00
if ( m_pClient - > m_pChat - > IsActive ( ) )
2011-03-01 17:31:20 +00:00
m_InputData . m_PlayerFlags = PLAYERFLAG_CHATTING ;
2010-05-29 07:25:38 +00:00
else if ( m_pClient - > m_pMenus - > IsActive ( ) )
2011-03-01 17:31:20 +00:00
m_InputData . m_PlayerFlags = PLAYERFLAG_IN_MENU ;
2008-08-27 15:48:50 +00:00
else
2011-03-01 17:31:20 +00:00
m_InputData . m_PlayerFlags = PLAYERFLAG_PLAYING ;
2011-04-13 18:37:12 +00:00
2011-03-01 17:31:20 +00:00
if ( m_pClient - > m_pScoreboard - > Active ( ) )
m_InputData . m_PlayerFlags | = PLAYERFLAG_SCOREBOARD ;
if ( m_LastData . m_PlayerFlags ! = m_InputData . m_PlayerFlags )
2010-05-29 07:25:38 +00:00
Send = true ;
2011-04-13 18:37:12 +00:00
2011-03-01 17:31:20 +00:00
m_LastData . m_PlayerFlags = m_InputData . m_PlayerFlags ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// we freeze the input if chat or menu is activated
2011-03-01 17:31:20 +00:00
if ( ! ( m_InputData . m_PlayerFlags & PLAYERFLAG_PLAYING ) )
2008-08-27 15:48:50 +00:00
{
2010-05-31 21:40:40 +00:00
OnReset ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
mem_copy ( pData , & m_InputData , sizeof ( m_InputData ) ) ;
2009-01-10 13:34:01 +00:00
// send once a second just to be sure
2010-05-29 07:25:38 +00:00
if ( time_get ( ) > LastSendTime + time_freq ( ) )
Send = true ;
2008-08-30 22:38:56 +00:00
}
2009-01-10 13:34:01 +00:00
else
2008-08-27 15:48:50 +00:00
{
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_InputData . m_TargetX = ( int ) m_MousePos . x ;
m_InputData . m_TargetY = ( int ) m_MousePos . y ;
if ( ! m_InputData . m_TargetX & & ! m_InputData . m_TargetY )
{
m_InputData . m_TargetX = 1 ;
m_MousePos . x = 1 ;
}
2011-04-13 18:37:12 +00:00
2009-01-10 13:34:01 +00:00
// set direction
2010-05-29 07:25:38 +00:00
m_InputData . m_Direction = 0 ;
if ( m_InputDirectionLeft & & ! m_InputDirectionRight )
m_InputData . m_Direction = - 1 ;
if ( ! m_InputDirectionLeft & & m_InputDirectionRight )
m_InputData . m_Direction = 1 ;
2009-01-10 13:34:01 +00:00
// stress testing
2010-05-29 07:25:38 +00:00
if ( g_Config . m_DbgStress )
2009-01-10 13:34:01 +00:00
{
2010-05-29 07:25:38 +00:00
float t = Client ( ) - > LocalTime ( ) ;
mem_zero ( & m_InputData , sizeof ( m_InputData ) ) ;
m_InputData . m_Direction = ( ( int ) t / 2 ) & 1 ;
m_InputData . m_Jump = ( ( int ) t ) ;
m_InputData . m_Fire = ( ( int ) ( t * 10 ) ) ;
m_InputData . m_Hook = ( ( int ) ( t * 2 ) ) & 1 ;
m_InputData . m_WantedWeapon = ( ( int ) t ) % NUM_WEAPONS ;
m_InputData . m_TargetX = ( int ) ( sinf ( t * 3 ) * 100.0f ) ;
m_InputData . m_TargetY = ( int ) ( cosf ( t * 3 ) * 100.0f ) ;
2009-01-10 13:34:01 +00:00
}
// check if we need to send input
2010-05-31 21:40:40 +00:00
if ( m_InputData . m_Direction ! = m_LastData . m_Direction ) Send = true ;
else if ( m_InputData . m_Jump ! = m_LastData . m_Jump ) Send = true ;
else if ( m_InputData . m_Fire ! = m_LastData . m_Fire ) Send = true ;
else if ( m_InputData . m_Hook ! = m_LastData . m_Hook ) Send = true ;
else if ( m_InputData . m_WantedWeapon ! = m_LastData . m_WantedWeapon ) Send = true ;
else if ( m_InputData . m_NextWeapon ! = m_LastData . m_NextWeapon ) Send = true ;
else if ( m_InputData . m_PrevWeapon ! = m_LastData . m_PrevWeapon ) Send = true ;
2009-01-10 13:34:01 +00:00
// send at at least 10hz
2010-05-29 07:25:38 +00:00
if ( time_get ( ) > LastSendTime + time_freq ( ) / 25 )
Send = true ;
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
// copy and return size
2010-05-31 21:40:40 +00:00
m_LastData = m_InputData ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( ! Send )
2008-08-27 15:48:50 +00:00
return 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
LastSendTime = time_get ( ) ;
mem_copy ( pData , & m_InputData , sizeof ( m_InputData ) ) ;
2011-04-13 18:37:12 +00:00
return sizeof ( m_InputData ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CControls : : OnRender ( )
2008-09-13 05:57:11 +00:00
{
// update target pos
2011-03-12 17:07:57 +00:00
if ( m_pClient - > m_Snap . m_pGameInfoObj & & ! ( m_pClient - > m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED | | m_pClient - > m_Snap . m_SpecInfo . m_Active ) )
2010-05-29 07:25:38 +00:00
m_TargetPos = m_pClient - > m_LocalCharacterPos + m_MousePos ;
2011-03-12 17:07:57 +00:00
else if ( m_pClient - > m_Snap . m_SpecInfo . m_Active & & m_pClient - > m_Snap . m_SpecInfo . m_UsePosition )
m_TargetPos = m_pClient - > m_Snap . m_SpecInfo . m_Position + m_MousePos ;
else
m_TargetPos = m_MousePos ;
2008-09-13 05:57:11 +00:00
}
2010-05-29 07:25:38 +00:00
bool CControls : : OnMouseMove ( float x , float y )
2008-08-27 15:48:50 +00:00
{
2011-03-12 17:07:57 +00:00
if ( m_pClient - > m_Snap . m_pGameInfoObj & & m_pClient - > m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED )
2008-11-16 15:39:22 +00:00
return false ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_MousePos + = vec2 ( x , y ) ; // TODO: ugly
2010-09-19 14:00:46 +00:00
ClampMousePos ( ) ;
return true ;
}
void CControls : : ClampMousePos ( )
{
2011-03-12 17:07:57 +00:00
if ( m_pClient - > m_Snap . m_SpecInfo . m_Active & & ! m_pClient - > m_Snap . m_SpecInfo . m_UsePosition )
2008-08-27 15:48:50 +00:00
{
2011-03-10 16:57:15 +00:00
m_MousePos . x = clamp ( m_MousePos . x , 200.0f , Collision ( ) - > GetWidth ( ) * 32 - 200.0f ) ;
m_MousePos . y = clamp ( m_MousePos . y , 200.0f , Collision ( ) - > GetHeight ( ) * 32 - 200.0f ) ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
}
else
{
2011-03-10 16:57:15 +00:00
float CameraMaxDistance = 200.0f ;
float FollowFactor = g_Config . m_ClMouseFollowfactor / 100.0f ;
float MouseMax = min ( CameraMaxDistance / FollowFactor + g_Config . m_ClMouseDeadzone , ( float ) g_Config . m_ClMouseMaxDistance ) ;
2011-04-13 18:37:12 +00:00
2011-03-10 16:57:15 +00:00
if ( length ( m_MousePos ) > MouseMax )
2010-05-29 07:25:38 +00:00
m_MousePos = normalize ( m_MousePos ) * MouseMax ;
2008-08-27 15:48:50 +00:00
}
2011-02-16 10:59:30 +00:00
}