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-08-31 11:56:04 +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
2014-06-16 11:29:18 +00:00
# include <SDL.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/config.h>
2014-09-13 10:31:39 +00:00
# include <engine/serverbrowser.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"
2014-06-16 11:29:18 +00:00
enum { LEFT_JOYSTICK_X = 0 , LEFT_JOYSTICK_Y = 1 ,
RIGHT_JOYSTICK_X = 2 , RIGHT_JOYSTICK_Y = 3 ,
SECOND_RIGHT_JOYSTICK_X = 20 , SECOND_RIGHT_JOYSTICK_Y = 21 ,
NUM_JOYSTICK_AXES = 22 } ;
2010-05-29 07:25:38 +00:00
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 ) ) ;
2014-04-28 16:21:10 +00:00
m_LastDummy = 0 ;
m_OtherFire = 0 ;
2014-06-16 11:29:18 +00:00
2014-08-27 01:57:14 +00:00
# if !defined(__ANDROID__)
2014-08-17 14:33:43 +00:00
if ( g_Config . m_InpJoystick )
2014-08-27 01:57:14 +00:00
# endif
2014-06-16 11:29:18 +00:00
{
2014-08-17 14:33:43 +00:00
SDL_Init ( SDL_INIT_JOYSTICK ) ;
m_Joystick = SDL_JoystickOpen ( 0 ) ;
if ( m_Joystick & & SDL_JoystickNumAxes ( m_Joystick ) < NUM_JOYSTICK_AXES )
{
SDL_JoystickClose ( m_Joystick ) ;
m_Joystick = NULL ;
}
2014-06-16 11:29:18 +00:00
2014-08-17 14:33:43 +00:00
m_Gamepad = SDL_JoystickOpen ( 2 ) ;
2014-06-16 11:29:18 +00:00
2014-08-17 14:33:43 +00:00
SDL_JoystickEventState ( SDL_QUERY ) ;
2014-06-16 11:29:18 +00:00
2014-08-17 14:33:43 +00:00
m_UsingGamepad = false ;
2014-06-16 11:29:18 +00:00
# if defined(CONF_FAMILY_UNIX)
2014-08-17 14:33:43 +00:00
if ( getenv ( " OUYA " ) )
m_UsingGamepad = true ;
2014-06-16 11:29:18 +00:00
# endif
2014-08-17 14:33:43 +00:00
}
2014-08-27 01:57:14 +00:00
# if !defined(__ANDROID__)
2014-08-17 14:33:43 +00:00
else
2014-08-27 01:49:42 +00:00
{
2014-08-17 14:33:43 +00:00
m_Joystick = NULL ;
2014-08-27 01:49:42 +00:00
m_Gamepad = NULL ;
2014-08-17 14:33:43 +00:00
m_UsingGamepad = false ;
2014-08-27 01:49:42 +00:00
}
2014-08-27 01:57:14 +00:00
# endif
2010-05-31 21:40:40 +00:00
}
void CControls : : OnReset ( )
{
2015-04-19 12:03:40 +00:00
ResetInput ( 0 ) ;
ResetInput ( 1 ) ;
2014-06-16 11:29:18 +00:00
m_JoystickFirePressed = false ;
m_JoystickRunPressed = false ;
m_JoystickTapTime = 0 ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
m_AmmoCount [ i ] = 0 ;
m_OldMouseX = m_OldMouseY = 0.0f ;
2008-08-27 15:48:50 +00:00
}
2017-02-28 09:08:14 +00:00
void CControls : : ResetInput ( int Dummy )
2014-07-07 23:41:45 +00:00
{
2017-02-28 09:08:14 +00:00
m_LastData [ Dummy ] . m_Direction = 0 ;
2015-04-19 12:03:40 +00:00
//m_LastData.m_Hook = 0;
// simulate releasing the fire button
2017-02-28 09:08:14 +00:00
if ( ( m_LastData [ Dummy ] . m_Fire & 1 ) ! = 0 )
m_LastData [ Dummy ] . m_Fire + + ;
m_LastData [ Dummy ] . m_Fire & = INPUT_STATE_MASK ;
m_LastData [ Dummy ] . m_Jump = 0 ;
m_InputData [ Dummy ] = m_LastData [ Dummy ] ;
m_InputDirectionLeft [ Dummy ] = 0 ;
m_InputDirectionRight [ Dummy ] = 0 ;
2014-07-07 23:41:45 +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 ( )
{
2015-04-19 12:03:40 +00:00
if ( g_Config . m_ClResetWantedWeaponOnDeath )
m_LastData [ g_Config . m_ClDummy ] . m_WantedWeapon = m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon = 0 ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
m_AmmoCount [ i ] = 0 ;
m_JoystickTapTime = 0 ; // Do not launch hook on first tap
2010-08-10 11:54:13 +00:00
}
2014-05-10 12:31:00 +00:00
struct CInputState
{
CControls * m_pControls ;
int * m_pVariable1 ;
2014-10-12 15:52:53 +00:00
int * m_pVariable2 ;
2014-05-10 12:31:00 +00:00
} ;
2011-08-13 00:11:06 +00:00
static void ConKeyInputState ( IConsole : : IResult * pResult , void * pUserData )
2008-08-27 15:48:50 +00:00
{
2014-05-10 12:31:00 +00:00
CInputState * pState = ( CInputState * ) pUserData ;
2014-09-06 23:53:20 +00:00
2014-09-13 10:31:39 +00:00
CServerInfo Info ;
pState - > m_pControls - > GameClient ( ) - > Client ( ) - > GetServerInfo ( & Info ) ;
2014-12-10 02:39:15 +00:00
if ( ( IsRace ( & Info ) | | IsDDRace ( & Info ) ) & & pState - > m_pControls - > GameClient ( ) - > m_Snap . m_SpecInfo . m_Active )
2014-09-06 23:53:20 +00:00
return ;
2014-10-12 15:52:53 +00:00
if ( g_Config . m_ClDummy )
* pState - > m_pVariable2 = pResult - > GetInteger ( 0 ) ;
else
* pState - > m_pVariable1 = pResult - > GetInteger ( 0 ) ;
2008-08-27 15:48:50 +00:00
}
2011-08-13 00:11:06 +00:00
static void ConKeyInputCounter ( IConsole : : IResult * pResult , void * pUserData )
2008-08-27 15:48:50 +00:00
{
2014-05-10 12:31:00 +00:00
CInputState * pState = ( CInputState * ) pUserData ;
2014-09-06 23:53:20 +00:00
2014-09-13 10:31:39 +00:00
CServerInfo Info ;
pState - > m_pControls - > GameClient ( ) - > Client ( ) - > GetServerInfo ( & Info ) ;
2014-12-10 02:39:15 +00:00
if ( ( IsRace ( & Info ) | | IsDDRace ( & Info ) ) & & pState - > m_pControls - > GameClient ( ) - > m_Snap . m_SpecInfo . m_Active )
2014-09-06 23:53:20 +00:00
return ;
2014-05-10 12:31:00 +00:00
int * v ;
2014-10-12 15:52:53 +00:00
if ( g_Config . m_ClDummy )
v = pState - > m_pVariable2 ;
else
v = pState - > m_pVariable1 ;
2014-05-10 12:31:00 +00:00
2010-05-29 07:25:38 +00:00
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 ;
2014-05-10 12:31:00 +00:00
int * m_pVariable1 ;
2014-10-12 15:52:53 +00:00
int * m_pVariable2 ;
2010-05-29 07:25:38 +00:00
int m_Value ;
2008-08-27 20:04:07 +00:00
} ;
2011-08-13 00:11:06 +00:00
static void ConKeyInputSet ( IConsole : : IResult * pResult , void * pUserData )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CInputSet * pSet = ( CInputSet * ) pUserData ;
if ( pResult - > GetInteger ( 0 ) )
2014-10-12 15:52:53 +00:00
{
if ( g_Config . m_ClDummy )
* pSet - > m_pVariable2 = pSet - > m_Value ;
else
* pSet - > m_pVariable1 = pSet - > m_Value ;
}
2008-08-27 15:48:50 +00:00
}
2011-08-13 00:11:06 +00:00
static void ConKeyInputNextPrevWeapon ( IConsole : : IResult * pResult , void * pUserData )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CInputSet * pSet = ( CInputSet * ) pUserData ;
2014-05-10 12:31:00 +00:00
ConKeyInputCounter ( pResult , pSet ) ;
2014-10-12 15:52:53 +00:00
pSet - > m_pControls - > m_InputData [ g_Config . m_ClDummy ] . 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
2014-10-12 15:52:53 +00:00
{ static CInputState s_State = { this , & m_InputDirectionLeft [ 0 ] , & m_InputDirectionLeft [ 1 ] } ; Console ( ) - > Register ( " +left " , " " , CFGFLAG_CLIENT , ConKeyInputState , ( void * ) & s_State , " Move left " ) ; }
{ static CInputState s_State = { this , & m_InputDirectionRight [ 0 ] , & m_InputDirectionRight [ 1 ] } ; Console ( ) - > Register ( " +right " , " " , CFGFLAG_CLIENT , ConKeyInputState , ( void * ) & s_State , " Move right " ) ; }
{ static CInputState s_State = { this , & m_InputData [ 0 ] . m_Jump , & m_InputData [ 1 ] . m_Jump } ; Console ( ) - > Register ( " +jump " , " " , CFGFLAG_CLIENT , ConKeyInputState , ( void * ) & s_State , " Jump " ) ; }
{ static CInputState s_State = { this , & m_InputData [ 0 ] . m_Hook , & m_InputData [ 1 ] . m_Hook } ; Console ( ) - > Register ( " +hook " , " " , CFGFLAG_CLIENT , ConKeyInputState , ( void * ) & s_State , " Hook " ) ; }
{ static CInputState s_State = { this , & m_InputData [ 0 ] . m_Fire , & m_InputData [ 1 ] . m_Fire } ; Console ( ) - > Register ( " +fire " , " " , CFGFLAG_CLIENT , ConKeyInputCounter , ( void * ) & s_State , " Fire " ) ; }
{ static CInputState s_State = { this , & m_ShowHookColl [ 0 ] , & m_ShowHookColl [ 1 ] } ; Console ( ) - > Register ( " +showhookcoll " , " " , CFGFLAG_CLIENT , ConKeyInputState , ( void * ) & s_State , " Show Hook Collision " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_WantedWeapon , & m_InputData [ 1 ] . m_WantedWeapon , 1 } ; Console ( ) - > Register ( " +weapon1 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to hammer " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_WantedWeapon , & m_InputData [ 1 ] . m_WantedWeapon , 2 } ; Console ( ) - > Register ( " +weapon2 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to gun " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_WantedWeapon , & m_InputData [ 1 ] . m_WantedWeapon , 3 } ; Console ( ) - > Register ( " +weapon3 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to shotgun " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_WantedWeapon , & m_InputData [ 1 ] . m_WantedWeapon , 4 } ; Console ( ) - > Register ( " +weapon4 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to grenade " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_WantedWeapon , & m_InputData [ 1 ] . m_WantedWeapon , 5 } ; Console ( ) - > Register ( " +weapon5 " , " " , CFGFLAG_CLIENT , ConKeyInputSet , ( void * ) & s_Set , " Switch to rifle " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_NextWeapon , & m_InputData [ 1 ] . m_NextWeapon , 0 } ; Console ( ) - > Register ( " +nextweapon " , " " , CFGFLAG_CLIENT , ConKeyInputNextPrevWeapon , ( void * ) & s_Set , " Switch to next weapon " ) ; }
{ static CInputSet s_Set = { this , & m_InputData [ 0 ] . m_PrevWeapon , & m_InputData [ 1 ] . m_PrevWeapon , 0 } ; Console ( ) - > Register ( " +prevweapon " , " " , CFGFLAG_CLIENT , ConKeyInputNextPrevWeapon , ( void * ) & s_Set , " Switch to previous weapon " ) ; }
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 )
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon = pMsg - > m_Weapon + 1 ;
2014-06-16 11:29:18 +00:00
// We don't really know ammo count, until we'll switch to that weapon, but any non-zero count will suffice here
m_AmmoCount [ pMsg - > m_Weapon % NUM_WEAPONS ] = 10 ;
2011-04-13 18:37:12 +00:00
}
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 ( ) )
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags = PLAYERFLAG_CHATTING ;
2010-05-29 07:25:38 +00:00
else if ( m_pClient - > m_pMenus - > IsActive ( ) )
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags = PLAYERFLAG_IN_MENU ;
2008-08-27 15:48:50 +00:00
else
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . 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 ( ) )
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags | = PLAYERFLAG_SCOREBOARD ;
2011-03-01 17:31:20 +00:00
2014-10-12 15:52:53 +00:00
if ( m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags ! = PLAYERFLAG_PLAYING )
2014-06-16 11:29:18 +00:00
m_JoystickTapTime = 0 ; // Do not launch hook on first tap
2014-10-12 15:52:53 +00:00
if ( m_pClient - > m_pControls - > m_ShowHookColl [ g_Config . m_ClDummy ] )
m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags | = PLAYERFLAG_AIM ;
2013-08-23 23:50:35 +00:00
2014-10-12 15:52:53 +00:00
if ( m_LastData [ g_Config . m_ClDummy ] . m_PlayerFlags ! = m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags )
2010-05-29 07:25:38 +00:00
Send = true ;
2011-04-13 18:37:12 +00:00
2014-10-12 15:52:53 +00:00
m_LastData [ g_Config . m_ClDummy ] . m_PlayerFlags = m_InputData [ g_Config . m_ClDummy ] . 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
2014-10-12 15:52:53 +00:00
if ( ! ( m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags & PLAYERFLAG_PLAYING ) )
2008-08-27 15:48:50 +00:00
{
2015-04-19 12:03:40 +00:00
ResetInput ( g_Config . m_ClDummy ) ;
2011-04-13 18:37:12 +00:00
2014-10-12 15:52:53 +00:00
mem_copy ( pData , & m_InputData [ g_Config . m_ClDummy ] , sizeof ( m_InputData [ 0 ] ) ) ;
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
{
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_TargetX = ( int ) m_MousePos [ g_Config . m_ClDummy ] . x ;
m_InputData [ g_Config . m_ClDummy ] . m_TargetY = ( int ) m_MousePos [ g_Config . m_ClDummy ] . y ;
if ( ! m_InputData [ g_Config . m_ClDummy ] . m_TargetX & & ! m_InputData [ g_Config . m_ClDummy ] . m_TargetY )
2010-05-29 07:25:38 +00:00
{
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_TargetX = 1 ;
2014-05-10 12:31:00 +00:00
m_MousePos [ g_Config . m_ClDummy ] . x = 1 ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2009-01-10 13:34:01 +00:00
// set direction
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Direction = 0 ;
if ( m_InputDirectionLeft [ g_Config . m_ClDummy ] & & ! m_InputDirectionRight [ g_Config . m_ClDummy ] )
m_InputData [ g_Config . m_ClDummy ] . m_Direction = - 1 ;
if ( ! m_InputDirectionLeft [ g_Config . m_ClDummy ] & & m_InputDirectionRight [ g_Config . m_ClDummy ] )
m_InputData [ g_Config . m_ClDummy ] . m_Direction = 1 ;
2009-01-10 13:34:01 +00:00
2015-02-16 10:19:42 +00:00
// dummy copy moves
if ( g_Config . m_ClDummyCopyMoves )
{
2017-02-28 09:08:14 +00:00
CNetObj_PlayerInput * pDummyInput = & m_pClient - > m_DummyInput ;
pDummyInput - > m_Direction = m_InputData [ g_Config . m_ClDummy ] . m_Direction ;
pDummyInput - > m_Hook = m_InputData [ g_Config . m_ClDummy ] . m_Hook ;
pDummyInput - > m_Jump = m_InputData [ g_Config . m_ClDummy ] . m_Jump ;
pDummyInput - > m_PlayerFlags = m_InputData [ g_Config . m_ClDummy ] . m_PlayerFlags ;
pDummyInput - > m_TargetX = m_InputData [ g_Config . m_ClDummy ] . m_TargetX ;
pDummyInput - > m_TargetY = m_InputData [ g_Config . m_ClDummy ] . m_TargetY ;
pDummyInput - > m_WantedWeapon = m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon ;
pDummyInput - > m_Fire + = m_InputData [ g_Config . m_ClDummy ] . m_Fire - m_LastData [ g_Config . m_ClDummy ] . m_Fire ;
pDummyInput - > m_NextWeapon + = m_InputData [ g_Config . m_ClDummy ] . m_NextWeapon - m_LastData [ g_Config . m_ClDummy ] . m_NextWeapon ;
pDummyInput - > m_PrevWeapon + = m_InputData [ g_Config . m_ClDummy ] . m_PrevWeapon - m_LastData [ g_Config . m_ClDummy ] . m_PrevWeapon ;
m_InputData [ ! g_Config . m_ClDummy ] = * pDummyInput ;
2015-02-16 10:19:42 +00:00
}
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 ( ) ;
2014-10-12 15:52:53 +00:00
mem_zero ( & m_InputData [ g_Config . m_ClDummy ] , sizeof ( m_InputData [ 0 ] ) ) ;
m_InputData [ g_Config . m_ClDummy ] . m_Direction = ( ( int ) t / 2 ) & 1 ;
m_InputData [ g_Config . m_ClDummy ] . m_Jump = ( ( int ) t ) ;
m_InputData [ g_Config . m_ClDummy ] . m_Fire = ( ( int ) ( t * 10 ) ) ;
m_InputData [ g_Config . m_ClDummy ] . m_Hook = ( ( int ) ( t * 2 ) ) & 1 ;
m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon = ( ( int ) t ) % NUM_WEAPONS ;
m_InputData [ g_Config . m_ClDummy ] . m_TargetX = ( int ) ( sinf ( t * 3 ) * 100.0f ) ;
m_InputData [ g_Config . m_ClDummy ] . m_TargetY = ( int ) ( cosf ( t * 3 ) * 100.0f ) ;
2014-04-28 16:21:10 +00:00
}
2009-01-10 13:34:01 +00:00
// check if we need to send input
2014-10-12 15:52:53 +00:00
if ( m_InputData [ g_Config . m_ClDummy ] . m_Direction ! = m_LastData [ g_Config . m_ClDummy ] . m_Direction ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_Jump ! = m_LastData [ g_Config . m_ClDummy ] . m_Jump ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_Fire ! = m_LastData [ g_Config . m_ClDummy ] . m_Fire ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_Hook ! = m_LastData [ g_Config . m_ClDummy ] . m_Hook ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon ! = m_LastData [ g_Config . m_ClDummy ] . m_WantedWeapon ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_NextWeapon ! = m_LastData [ g_Config . m_ClDummy ] . m_NextWeapon ) Send = true ;
else if ( m_InputData [ g_Config . m_ClDummy ] . m_PrevWeapon ! = m_LastData [ g_Config . m_ClDummy ] . 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 ;
2014-04-30 13:21:23 +00:00
if ( m_pClient - > m_Snap . m_pLocalCharacter & & m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon = = WEAPON_NINJA
2014-10-12 15:52:53 +00:00
& & ( m_InputData [ g_Config . m_ClDummy ] . m_Direction | | m_InputData [ g_Config . m_ClDummy ] . m_Jump | | m_InputData [ g_Config . m_ClDummy ] . m_Hook ) )
2014-04-30 13:21:23 +00:00
Send = true ;
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
// copy and return size
2014-10-12 15:52:53 +00:00
m_LastData [ g_Config . m_ClDummy ] = m_InputData [ g_Config . m_ClDummy ] ;
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 ( ) ;
2014-10-12 15:52:53 +00:00
mem_copy ( pData , & m_InputData [ g_Config . m_ClDummy ] , sizeof ( m_InputData [ 0 ] ) ) ;
return sizeof ( m_InputData [ 0 ] ) ;
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
{
2014-06-16 11:29:18 +00:00
enum {
JOYSTICK_RUN_DISTANCE = 65536 / 8 ,
GAMEPAD_DEAD_ZONE = 65536 / 8 ,
} ;
int64 CurTime = time_get ( ) ;
bool FireWasPressed = false ;
if ( m_Joystick )
{
// Get input from left joystick
int RunX = SDL_JoystickGetAxis ( m_Joystick , LEFT_JOYSTICK_X ) ;
int RunY = SDL_JoystickGetAxis ( m_Joystick , LEFT_JOYSTICK_Y ) ;
bool RunPressed = ( RunX ! = 0 | | RunY ! = 0 ) ;
// Get input from right joystick
int AimX = SDL_JoystickGetAxis ( m_Joystick , SECOND_RIGHT_JOYSTICK_X ) ;
int AimY = SDL_JoystickGetAxis ( m_Joystick , SECOND_RIGHT_JOYSTICK_Y ) ;
bool AimPressed = ( AimX ! = 0 | | AimY ! = 0 ) ;
// Get input from another right joystick
int HookX = SDL_JoystickGetAxis ( m_Joystick , RIGHT_JOYSTICK_X ) ;
int HookY = SDL_JoystickGetAxis ( m_Joystick , RIGHT_JOYSTICK_Y ) ;
bool HookPressed = ( HookX ! = 0 | | HookY ! = 0 ) ;
if ( m_JoystickRunPressed ! = RunPressed )
{
if ( RunPressed )
{
if ( m_JoystickTapTime + time_freq ( ) > CurTime ) // Tap in less than 1 second to jump
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Jump = 1 ;
2014-06-16 11:29:18 +00:00
}
else
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Jump = 0 ;
2014-06-16 11:29:18 +00:00
m_JoystickTapTime = CurTime ;
}
m_JoystickRunPressed = RunPressed ;
if ( RunPressed )
{
2014-10-12 15:52:53 +00:00
m_InputDirectionLeft [ g_Config . m_ClDummy ] = ( RunX < - JOYSTICK_RUN_DISTANCE ) ;
m_InputDirectionRight [ g_Config . m_ClDummy ] = ( RunX > JOYSTICK_RUN_DISTANCE ) ;
2014-06-16 11:29:18 +00:00
}
// Move 500ms in the same direction, to prevent speed bump when tapping
if ( ! RunPressed & & m_JoystickTapTime + time_freq ( ) / 2 > CurTime )
{
2014-10-12 15:52:53 +00:00
m_InputDirectionLeft [ g_Config . m_ClDummy ] = 0 ;
m_InputDirectionRight [ g_Config . m_ClDummy ] = 0 ;
2014-06-16 11:29:18 +00:00
}
if ( HookPressed )
{
m_MousePos [ g_Config . m_ClDummy ] = vec2 ( HookX / 30 , HookY / 30 ) ;
ClampMousePos ( ) ;
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Hook = 1 ;
2014-06-16 11:29:18 +00:00
}
else
{
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Hook = 0 ;
2014-06-16 11:29:18 +00:00
}
if ( AimPressed )
{
m_MousePos [ g_Config . m_ClDummy ] = vec2 ( AimX / 30 , AimY / 30 ) ;
ClampMousePos ( ) ;
}
if ( AimPressed ! = m_JoystickFirePressed )
{
// Fire when releasing joystick
if ( ! AimPressed )
{
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_Fire + + ;
if ( ( bool ) ( m_InputData [ g_Config . m_ClDummy ] . m_Fire % 2 ) ! = AimPressed )
m_InputData [ g_Config . m_ClDummy ] . m_Fire + + ;
2014-06-16 11:29:18 +00:00
FireWasPressed = true ;
}
}
m_JoystickFirePressed = AimPressed ;
}
if ( m_Gamepad )
{
// Get input from left joystick
int RunX = SDL_JoystickGetAxis ( m_Gamepad , LEFT_JOYSTICK_X ) ;
int RunY = SDL_JoystickGetAxis ( m_Gamepad , LEFT_JOYSTICK_Y ) ;
if ( m_UsingGamepad )
{
2014-10-12 15:52:53 +00:00
m_InputDirectionLeft [ g_Config . m_ClDummy ] = ( RunX < - GAMEPAD_DEAD_ZONE ) ;
m_InputDirectionRight [ g_Config . m_ClDummy ] = ( RunX > GAMEPAD_DEAD_ZONE ) ;
2014-06-16 11:29:18 +00:00
}
// Get input from right joystick
int AimX = SDL_JoystickGetAxis ( m_Gamepad , RIGHT_JOYSTICK_X ) ;
int AimY = SDL_JoystickGetAxis ( m_Gamepad , RIGHT_JOYSTICK_Y ) ;
if ( abs ( AimX ) > GAMEPAD_DEAD_ZONE | | abs ( AimY ) > GAMEPAD_DEAD_ZONE )
{
m_MousePos [ g_Config . m_ClDummy ] = vec2 ( AimX / 30 , AimY / 30 ) ;
ClampMousePos ( ) ;
}
if ( ! m_UsingGamepad & & ( abs ( AimX ) > GAMEPAD_DEAD_ZONE | | abs ( AimY ) > GAMEPAD_DEAD_ZONE | | abs ( RunX ) > GAMEPAD_DEAD_ZONE | | abs ( RunY ) > GAMEPAD_DEAD_ZONE ) )
{
UI ( ) - > AndroidShowScreenKeys ( false ) ;
m_UsingGamepad = true ;
}
}
2014-10-26 01:01:03 +00:00
CServerInfo Info ;
GameClient ( ) - > Client ( ) - > GetServerInfo ( & Info ) ;
2014-12-10 02:39:15 +00:00
if ( g_Config . m_ClAutoswitchWeaponsOutOfAmmo & & ! IsRace ( & Info ) & & ! IsDDRace ( & Info ) & & m_pClient - > m_Snap . m_pLocalCharacter )
2014-06-16 11:29:18 +00:00
{
// Keep track of ammo count, we know weapon ammo only when we switch to that weapon, this is tracked on server and protocol does not track that
m_AmmoCount [ m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon % NUM_WEAPONS ] = m_pClient - > m_Snap . m_pLocalCharacter - > m_AmmoCount ;
// Autoswitch weapon if we're out of ammo
2014-10-12 15:52:53 +00:00
if ( ( m_InputData [ g_Config . m_ClDummy ] . m_Fire % 2 ! = 0 | | FireWasPressed ) & &
2014-06-16 11:29:18 +00:00
m_pClient - > m_Snap . m_pLocalCharacter - > m_AmmoCount = = 0 & &
m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon ! = WEAPON_HAMMER & &
m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon ! = WEAPON_NINJA )
{
int w ;
for ( w = WEAPON_RIFLE ; w > WEAPON_GUN ; w - - )
{
if ( w = = m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon )
continue ;
if ( m_AmmoCount [ w ] > 0 )
break ;
}
if ( w ! = m_pClient - > m_Snap . m_pLocalCharacter - > m_Weapon )
2014-10-12 15:52:53 +00:00
m_InputData [ g_Config . m_ClDummy ] . m_WantedWeapon = w + 1 ;
2014-06-16 11:29:18 +00:00
}
}
2008-09-13 05:57:11 +00:00
// update target pos
2012-01-09 23:49:31 +00:00
if ( m_pClient - > m_Snap . m_pGameInfoObj & & ! m_pClient - > m_Snap . m_SpecInfo . m_Active )
2014-05-10 12:31:00 +00:00
m_TargetPos [ g_Config . m_ClDummy ] = m_pClient - > m_LocalCharacterPos + m_MousePos [ g_Config . m_ClDummy ] ;
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 )
2014-05-10 12:31:00 +00:00
m_TargetPos [ g_Config . m_ClDummy ] = m_pClient - > m_Snap . m_SpecInfo . m_Position + m_MousePos [ g_Config . m_ClDummy ] ;
2011-03-12 17:07:57 +00:00
else
2014-05-10 12:31:00 +00:00
m_TargetPos [ g_Config . m_ClDummy ] = m_MousePos [ g_Config . m_ClDummy ] ;
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-11-30 00:47:35 +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 & & m_pClient - > m_pChat - > IsActive ( ) ) )
2008-11-16 15:39:22 +00:00
return false ;
2011-04-13 18:37:12 +00:00
2014-06-16 11:29:18 +00:00
# if defined(__ANDROID__) // No relative mouse on Android
// We're using joystick on Android, mouse is disabled
if ( m_OldMouseX ! = x | | m_OldMouseY ! = y )
{
m_OldMouseX = x ;
m_OldMouseY = y ;
2016-04-30 15:59:58 +00:00
m_MousePos [ g_Config . m_ClDummy ] = vec2 ( ( x - Graphics ( ) - > Width ( ) / 2 ) , ( y - Graphics ( ) - > Height ( ) / 2 ) ) ;
2014-06-16 11:29:18 +00:00
ClampMousePos ( ) ;
}
# else
2014-05-10 12:31:00 +00:00
m_MousePos [ g_Config . m_ClDummy ] + = vec2 ( x , y ) ; // TODO: ugly
2010-09-19 14:00:46 +00:00
ClampMousePos ( ) ;
2014-06-16 11:29:18 +00:00
# endif
2010-09-19 14:00:46 +00:00
return true ;
}
void CControls : : ClampMousePos ( )
{
2016-04-30 19:28:44 +00:00
if ( m_pClient - > m_Snap . m_SpecInfo . m_Active & & m_pClient - > m_Snap . m_SpecInfo . m_SpectatorID < 0 )
2008-08-27 15:48:50 +00:00
{
2014-05-10 12:31:00 +00:00
m_MousePos [ g_Config . m_ClDummy ] . x = clamp ( m_MousePos [ g_Config . m_ClDummy ] . x , 200.0f , Collision ( ) - > GetWidth ( ) * 32 - 200.0f ) ;
m_MousePos [ g_Config . m_ClDummy ] . y = clamp ( m_MousePos [ g_Config . m_ClDummy ] . y , 200.0f , Collision ( ) - > GetHeight ( ) * 32 - 200.0f ) ;
2008-08-27 15:48:50 +00:00
}
else
{
2011-03-10 16:57:15 +00:00
float CameraMaxDistance = 200.0f ;
2015-08-27 18:26:05 +00:00
float FollowFactor = ( g_Config . m_ClDyncam ? g_Config . m_ClDyncamFollowFactor : g_Config . m_ClMouseFollowfactor ) / 100.0f ;
float DeadZone = g_Config . m_ClDyncam ? g_Config . m_ClDyncamDeadzone : g_Config . m_ClMouseDeadzone ;
float MaxDistance = g_Config . m_ClDyncam ? g_Config . m_ClDyncamMaxDistance : g_Config . m_ClMouseMaxDistance ;
float MouseMax = min ( CameraMaxDistance / FollowFactor + DeadZone , MaxDistance ) ;
2011-04-13 18:37:12 +00:00
2014-05-10 12:31:00 +00:00
if ( length ( m_MousePos [ g_Config . m_ClDummy ] ) > MouseMax )
m_MousePos [ g_Config . m_ClDummy ] = normalize ( m_MousePos [ g_Config . m_ClDummy ] ) * MouseMax ;
2008-08-27 15:48:50 +00:00
}
2011-02-16 10:59:30 +00:00
}