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. */
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <base/math.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <engine/shared/config.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2021-01-11 16:54:33 +00:00
|
|
|
#include <game/client/components/camera.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#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>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
#include <game/collision.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2021-06-06 19:05:20 +00:00
|
|
|
#include <base/vmath.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));
|
2014-04-28 16:21:10 +00:00
|
|
|
m_LastDummy = 0;
|
|
|
|
m_OtherFire = 0;
|
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
|
|
|
|
2020-10-26 14:14:07 +00:00
|
|
|
for(int &AmmoCount : m_AmmoCount)
|
|
|
|
AmmoCount = 0;
|
2014-06-16 11:29:18 +00:00
|
|
|
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;
|
2017-03-06 18:45:39 +00:00
|
|
|
//m_LastData[Dummy].m_Hook = 0;
|
2015-04-19 12:03:40 +00:00
|
|
|
// simulate releasing the fire button
|
2020-09-26 19:41:58 +00:00
|
|
|
if((m_LastData[Dummy].m_Fire & 1) != 0)
|
2017-02-28 09:08:14 +00:00
|
|
|
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()
|
|
|
|
{
|
2020-10-26 14:14:07 +00:00
|
|
|
for(int &AmmoCount : m_AmmoCount)
|
|
|
|
AmmoCount = 0;
|
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
|
|
|
|
2019-06-03 19:52:14 +00:00
|
|
|
if(pState->m_pControls->GameClient()->m_GameInfo.m_BugDDRaceInput && pState->m_pControls->GameClient()->m_Snap.m_SpecInfo.m_Active)
|
2014-09-06 23:53:20 +00:00
|
|
|
return;
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(g_Config.m_ClDummy)
|
2014-10-12 15:52:53 +00:00
|
|
|
*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
|
|
|
|
2019-06-03 19:52:14 +00:00
|
|
|
if(pState->m_pControls->GameClient()->m_GameInfo.m_BugDDRaceInput && 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;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(g_Config.m_ClDummy)
|
2014-10-12 15:52:53 +00:00
|
|
|
v = pState->m_pVariable2;
|
|
|
|
else
|
|
|
|
v = pState->m_pVariable1;
|
2014-05-10 12:31:00 +00:00
|
|
|
|
2020-09-26 19:41:58 +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
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(g_Config.m_ClDummy)
|
2014-10-12 15:52:53 +00:00
|
|
|
*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
|
2020-09-26 19:41:58 +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 laser");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
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)
|
2020-09-26 19:41:58 +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
|
2020-09-26 19:41:58 +00:00
|
|
|
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
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
static int64_t LastSendTime = 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
bool Send = false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// update player state
|
2021-07-12 09:43:56 +00:00
|
|
|
if(m_pClient->m_Chat.IsActive())
|
2014-10-12 15:52:53 +00:00
|
|
|
m_InputData[g_Config.m_ClDummy].m_PlayerFlags = PLAYERFLAG_CHATTING;
|
2021-07-12 09:43:56 +00:00
|
|
|
else if(m_pClient->m_Menus.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
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
if(m_pClient->m_Scoreboard.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
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
if(m_pClient->m_Controls.m_ShowHookColl[g_Config.m_ClDummy])
|
2014-10-12 15:52:53 +00:00
|
|
|
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
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!(m_InputData[g_Config.m_ClDummy].m_PlayerFlags & PLAYERFLAG_PLAYING))
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2019-06-03 19:52:14 +00:00
|
|
|
if(!GameClient()->m_GameInfo.m_BugDDRaceInput)
|
2017-07-10 20:24: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
|
|
|
|
2018-12-28 23:04:40 +00:00
|
|
|
// set the target anyway though so that we can keep seeing our surroundings,
|
|
|
|
// even if chat or menu are activated
|
|
|
|
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;
|
|
|
|
|
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
|
|
|
}
|
2019-04-26 19:36:49 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(g_Config.m_ClDummyControl)
|
|
|
|
{
|
2018-03-14 12:14:18 +00:00
|
|
|
CNetObj_PlayerInput *pDummyInput = &m_pClient->m_DummyInput;
|
|
|
|
pDummyInput->m_Jump = g_Config.m_ClDummyJump;
|
|
|
|
pDummyInput->m_Fire = g_Config.m_ClDummyFire;
|
|
|
|
pDummyInput->m_Hook = g_Config.m_ClDummyHook;
|
|
|
|
}
|
2015-02-16 10:19:42 +00:00
|
|
|
|
2009-01-10 13:34:01 +00:00
|
|
|
// stress testing
|
2017-06-02 18:45:09 +00:00
|
|
|
#ifdef CONF_DEBUG
|
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]));
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
m_InputData[g_Config.m_ClDummy].m_Direction = ((int)t / 2) & 1;
|
2014-10-12 15:52:53 +00:00
|
|
|
m_InputData[g_Config.m_ClDummy].m_Jump = ((int)t);
|
2020-09-26 19:41:58 +00:00
|
|
|
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
|
|
|
}
|
2017-06-02 18:45:09 +00:00
|
|
|
#endif
|
2014-04-28 16:21:10 +00:00
|
|
|
|
2009-01-10 13:34:01 +00:00
|
|
|
// check if we need to send input
|
2020-09-26 19:41:58 +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
|
2020-09-26 19:41:58 +00:00
|
|
|
if(time_get() > LastSendTime + time_freq() / 25)
|
2010-05-29 07:25:38 +00:00
|
|
|
Send = true;
|
2014-04-30 13:21:23 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_pClient->m_Snap.m_pLocalCharacter && m_pClient->m_Snap.m_pLocalCharacter->m_Weapon == WEAPON_NINJA && (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
|
|
|
{
|
2019-06-03 19:52:14 +00:00
|
|
|
if(g_Config.m_ClAutoswitchWeaponsOutOfAmmo && !GameClient()->m_GameInfo.m_UnlimitedAmmo && 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
|
2020-09-26 19:41:58 +00:00
|
|
|
m_AmmoCount[m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS] = m_pClient->m_Snap.m_pLocalCharacter->m_AmmoCount;
|
2014-06-16 11:29:18 +00:00
|
|
|
// Autoswitch weapon if we're out of ammo
|
2022-06-06 11:20:05 +00:00
|
|
|
if(m_InputData[g_Config.m_ClDummy].m_Fire % 2 != 0 &&
|
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 &&
|
2020-09-26 19:41:58 +00:00
|
|
|
m_pClient->m_Snap.m_pLocalCharacter->m_Weapon != WEAPON_NINJA)
|
2014-06-16 11:29:18 +00:00
|
|
|
{
|
|
|
|
int w;
|
2020-09-26 19:41:58 +00:00
|
|
|
for(w = WEAPON_LASER; w > WEAPON_GUN; w--)
|
2014-06-16 11:29:18 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(w == m_pClient->m_Snap.m_pLocalCharacter->m_Weapon)
|
2014-06-16 11:29:18 +00:00
|
|
|
continue;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_AmmoCount[w] > 0)
|
2014-06-16 11:29:18 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
if(w != m_pClient->m_Snap.m_pLocalCharacter->m_Weapon)
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-06-06 20:03:24 +00:00
|
|
|
bool CControls::OnCursorMove(float x, float y, IInput::ECursorType CursorType)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2022-06-06 20:03:24 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && (m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED))
|
2021-10-23 11:48:21 +00:00
|
|
|
return false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2022-06-15 11:00:27 +00:00
|
|
|
if(CursorType == IInput::CURSOR_JOYSTICK && g_Config.m_InpControllerAbsolute && m_pClient->m_Snap.m_pGameInfoObj && !m_pClient->m_Snap.m_SpecInfo.m_Active)
|
2019-01-11 08:39:53 +00:00
|
|
|
{
|
2022-06-06 20:03:24 +00:00
|
|
|
float AbsX = 0.0f, AbsY = 0.0f;
|
|
|
|
if(Input()->GetActiveJoystick()->Absolute(&AbsX, &AbsY))
|
|
|
|
m_MousePos[g_Config.m_ClDummy] = vec2(AbsX, AbsY) * GetMaxMouseDistance();
|
|
|
|
return true;
|
2019-01-11 08:39:53 +00:00
|
|
|
}
|
2021-01-11 16:54:33 +00:00
|
|
|
|
2022-06-06 20:03:24 +00:00
|
|
|
float Factor = 1.0f;
|
|
|
|
if(g_Config.m_ClDyncam && g_Config.m_ClDyncamMousesens)
|
2021-01-11 16:54:33 +00:00
|
|
|
{
|
2022-06-06 20:03:24 +00:00
|
|
|
Factor = g_Config.m_ClDyncamMousesens / 100.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch(CursorType)
|
|
|
|
{
|
|
|
|
case IInput::CURSOR_MOUSE:
|
|
|
|
Factor = g_Config.m_InpMousesens / 100.0f;
|
|
|
|
break;
|
|
|
|
case IInput::CURSOR_JOYSTICK:
|
2022-06-15 11:00:27 +00:00
|
|
|
Factor = g_Config.m_InpControllerSens / 100.0f;
|
2022-06-06 20:03:24 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbg_msg("assert", "CControls::OnCursorMove CursorType %d", (int)CursorType);
|
|
|
|
dbg_break();
|
|
|
|
break;
|
|
|
|
}
|
2021-01-11 16:54:33 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 20:03:24 +00:00
|
|
|
if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID < 0)
|
|
|
|
Factor *= m_pClient->m_Camera.m_Zoom;
|
2010-09-19 14:00:46 +00:00
|
|
|
|
2022-06-06 20:03:24 +00:00
|
|
|
m_MousePos[g_Config.m_ClDummy] += vec2(x, y) * Factor;
|
|
|
|
ClampMousePos();
|
2021-10-23 11:48:21 +00:00
|
|
|
return true;
|
2010-09-19 14:00:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2022-04-09 13:24:57 +00:00
|
|
|
m_MousePos[g_Config.m_ClDummy].x = clamp(m_MousePos[g_Config.m_ClDummy].x, 0.0f, Collision()->GetWidth() * 32.0f);
|
|
|
|
m_MousePos[g_Config.m_ClDummy].y = clamp(m_MousePos[g_Config.m_ClDummy].y, 0.0f, Collision()->GetHeight() * 32.0f);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-06-06 20:03:24 +00:00
|
|
|
float MouseMax = GetMaxMouseDistance();
|
2019-04-04 18:17:11 +00:00
|
|
|
float MinDistance = g_Config.m_ClDyncam ? g_Config.m_ClDyncamMinDistance : g_Config.m_ClMouseMinDistance;
|
2019-12-18 19:58:42 +00:00
|
|
|
float MouseMin = MinDistance;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-06-06 19:05:20 +00:00
|
|
|
float MDistance = length(m_MousePos[g_Config.m_ClDummy]);
|
|
|
|
if(MDistance < 0.001f)
|
|
|
|
{
|
|
|
|
m_MousePos[g_Config.m_ClDummy].x = 0.001f;
|
|
|
|
m_MousePos[g_Config.m_ClDummy].y = 0;
|
|
|
|
MDistance = 0.001f;
|
|
|
|
}
|
|
|
|
if(MDistance < MouseMin)
|
|
|
|
m_MousePos[g_Config.m_ClDummy] = normalize_pre_length(m_MousePos[g_Config.m_ClDummy], MDistance) * MouseMin;
|
|
|
|
MDistance = length(m_MousePos[g_Config.m_ClDummy]);
|
|
|
|
if(MDistance > MouseMax)
|
|
|
|
m_MousePos[g_Config.m_ClDummy] = normalize_pre_length(m_MousePos[g_Config.m_ClDummy], MDistance) * MouseMax;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-02-16 10:59:30 +00:00
|
|
|
}
|
2022-06-06 20:03:24 +00:00
|
|
|
|
|
|
|
float CControls::GetMaxMouseDistance() const
|
|
|
|
{
|
|
|
|
float CameraMaxDistance = 200.0f;
|
|
|
|
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;
|
|
|
|
return minimum((FollowFactor != 0 ? CameraMaxDistance / FollowFactor + DeadZone : MaxDistance), MaxDistance);
|
|
|
|
}
|