You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
11 KiB
439 lines
11 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Entities that capture the player's UI and move it into game design |
|
// as outputs. |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "entitylist.h" |
|
#include "util.h" |
|
#include "physics.h" |
|
#include "entityoutput.h" |
|
#include "player.h" |
|
#include "in_buttons.h" |
|
#include "basecombatweapon.h" |
|
#include "baseviewmodel.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//---------------------------------------------------------------- |
|
// Spawn flags |
|
//---------------------------------------------------------------- |
|
#define SF_GAMEUI_FREEZE_PLAYER 32 |
|
#define SF_GAMEUI_HIDE_WEAPON 64 |
|
#define SF_GAMEUI_USE_DEACTIVATES 128 |
|
#define SF_GAMEUI_JUMP_DEACTIVATES 256 |
|
|
|
|
|
class CGameUI : public CBaseEntity |
|
{ |
|
public: |
|
DECLARE_CLASS( CGameUI, CBaseEntity ); |
|
|
|
DECLARE_DATADESC(); |
|
|
|
// Input handlers |
|
void InputDeactivate( inputdata_t &inputdata ); |
|
void InputActivate( inputdata_t &inputdata ); |
|
|
|
void Think( void ); |
|
void Deactivate( CBaseEntity *pActivator ); |
|
|
|
float m_flFieldOfView; |
|
CHandle<CBaseCombatWeapon> m_hSaveWeapon; |
|
|
|
COutputEvent m_playerOn; |
|
COutputEvent m_playerOff; |
|
|
|
COutputEvent m_pressedMoveLeft; |
|
COutputEvent m_pressedMoveRight; |
|
COutputEvent m_pressedForward; |
|
COutputEvent m_pressedBack; |
|
COutputEvent m_pressedAttack; |
|
COutputEvent m_pressedAttack2; |
|
|
|
COutputEvent m_unpressedMoveLeft; |
|
COutputEvent m_unpressedMoveRight; |
|
COutputEvent m_unpressedForward; |
|
COutputEvent m_unpressedBack; |
|
COutputEvent m_unpressedAttack; |
|
COutputEvent m_unpressedAttack2; |
|
|
|
COutputFloat m_xaxis; |
|
COutputFloat m_yaxis; |
|
COutputFloat m_attackaxis; |
|
COutputFloat m_attack2axis; |
|
|
|
bool m_bForceUpdate; |
|
int m_nLastButtonState; |
|
|
|
CHandle<CBasePlayer> m_player; |
|
}; |
|
|
|
|
|
BEGIN_DATADESC( CGameUI ) |
|
|
|
DEFINE_KEYFIELD( m_flFieldOfView, FIELD_FLOAT, "FieldOfView" ), |
|
DEFINE_FIELD( m_hSaveWeapon, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_bForceUpdate, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_player, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_nLastButtonState, FIELD_INTEGER ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "Activate", InputActivate ), |
|
|
|
DEFINE_OUTPUT( m_playerOn, "PlayerOn" ), |
|
DEFINE_OUTPUT( m_playerOff, "PlayerOff" ), |
|
|
|
DEFINE_OUTPUT( m_pressedMoveLeft, "PressedMoveLeft" ), |
|
DEFINE_OUTPUT( m_pressedMoveRight, "PressedMoveRight" ), |
|
DEFINE_OUTPUT( m_pressedForward, "PressedForward" ), |
|
DEFINE_OUTPUT( m_pressedBack, "PressedBack" ), |
|
DEFINE_OUTPUT( m_pressedAttack, "PressedAttack" ), |
|
DEFINE_OUTPUT( m_pressedAttack2, "PressedAttack2" ), |
|
|
|
DEFINE_OUTPUT( m_unpressedMoveLeft, "UnpressedMoveLeft" ), |
|
DEFINE_OUTPUT( m_unpressedMoveRight, "UnpressedMoveRight" ), |
|
DEFINE_OUTPUT( m_unpressedForward, "UnpressedForward" ), |
|
DEFINE_OUTPUT( m_unpressedBack, "UnpressedBack" ), |
|
DEFINE_OUTPUT( m_unpressedAttack, "UnpressedAttack" ), |
|
DEFINE_OUTPUT( m_unpressedAttack2, "UnpressedAttack2" ), |
|
|
|
DEFINE_OUTPUT( m_xaxis, "XAxis" ), |
|
DEFINE_OUTPUT( m_yaxis, "YAxis" ), |
|
DEFINE_OUTPUT( m_attackaxis, "AttackAxis" ), |
|
DEFINE_OUTPUT( m_attack2axis, "Attack2Axis" ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( game_ui, CGameUI ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CGameUI::InputDeactivate( inputdata_t &inputdata ) |
|
{ |
|
Deactivate( inputdata.pActivator ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CGameUI::Deactivate( CBaseEntity *pActivator ) |
|
{ |
|
CBasePlayer *pPlayer = m_player; |
|
|
|
AssertMsg(pPlayer, "CGameUI deactivated without a player!"); |
|
|
|
if (pPlayer) |
|
{ |
|
// Re-enable player motion |
|
if ( FBitSet( m_spawnflags, SF_GAMEUI_FREEZE_PLAYER ) ) |
|
{ |
|
m_player->RemoveFlag( FL_ATCONTROLS ); |
|
} |
|
|
|
// Restore weapons |
|
if ( FBitSet( m_spawnflags, SF_GAMEUI_HIDE_WEAPON ) ) |
|
{ |
|
// Turn the hud back on |
|
pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION; |
|
|
|
if ( m_hSaveWeapon.Get() ) |
|
{ |
|
m_player->Weapon_Switch( m_hSaveWeapon.Get() ); |
|
m_hSaveWeapon = NULL; |
|
} |
|
|
|
if ( pPlayer->GetActiveWeapon() ) |
|
{ |
|
pPlayer->GetActiveWeapon()->Deploy(); |
|
} |
|
} |
|
|
|
// Announce that the player is no longer controlling through us |
|
m_playerOff.FireOutput( pPlayer, this, 0 ); |
|
|
|
// Clear out the axis controls |
|
m_xaxis.Set( 0, pPlayer, this ); |
|
m_yaxis.Set( 0, pPlayer, this ); |
|
m_attackaxis.Set( 0, pPlayer, this ); |
|
m_attack2axis.Set( 0, pPlayer, this ); |
|
m_nLastButtonState = 0; |
|
m_player = NULL; |
|
} |
|
else |
|
{ |
|
Warning("%s Deactivate(): I have no player when called by %s!\n", GetEntityName().ToCStr(), pActivator->GetEntityName().ToCStr()); |
|
} |
|
|
|
// Stop thinking |
|
SetNextThink( TICK_NEVER_THINK ); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : |
|
//------------------------------------------------------------------------------ |
|
void CGameUI::InputActivate( inputdata_t &inputdata ) |
|
{ |
|
CBasePlayer *pPlayer; |
|
|
|
// Determine if we're specifying this as an override parameter |
|
if ( inputdata.value.StringID() != NULL_STRING ) |
|
{ |
|
CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller ); |
|
if ( pEntity == NULL || pEntity->IsPlayer() == false ) |
|
{ |
|
Warning( "%s InputActivate: entity %s not found or is not a player!\n", GetEntityName().ToCStr(), inputdata.value.String() ); |
|
return; |
|
} |
|
|
|
pPlayer = ToBasePlayer( pEntity ); |
|
} |
|
else |
|
{ |
|
// Otherwise try to use the activator |
|
if ( inputdata.pActivator == NULL || inputdata.pActivator->IsPlayer() == false ) |
|
{ |
|
Warning( "%s InputActivate: invalid or missing !activator!\n", GetEntityName().ToCStr() ); |
|
return; |
|
} |
|
|
|
pPlayer = ToBasePlayer( inputdata.pActivator ); |
|
} |
|
|
|
// If another player is already using these controls3, ignore this activation |
|
if ( m_player.Get() != NULL && pPlayer != m_player.Get() ) |
|
{ |
|
// TODO: We could allow this by calling Deactivate() at this point and continuing on -- jdw |
|
return; |
|
} |
|
|
|
// Setup our internal data |
|
m_player = pPlayer; |
|
m_playerOn.FireOutput( pPlayer, this, 0 ); |
|
|
|
// Turn the hud off |
|
SetNextThink( gpGlobals->curtime ); |
|
|
|
// Disable player's motion |
|
if ( FBitSet( m_spawnflags, SF_GAMEUI_FREEZE_PLAYER ) ) |
|
{ |
|
m_player->AddFlag( FL_ATCONTROLS ); |
|
} |
|
|
|
// Store off and hide the currently held weapon |
|
if ( FBitSet( m_spawnflags, SF_GAMEUI_HIDE_WEAPON ) ) |
|
{ |
|
m_player->m_Local.m_iHideHUD |= HIDEHUD_WEAPONSELECTION; |
|
|
|
if ( m_player->GetActiveWeapon() ) |
|
{ |
|
m_hSaveWeapon = m_player->GetActiveWeapon(); |
|
|
|
m_player->GetActiveWeapon()->Holster(); |
|
m_player->ClearActiveWeapon(); |
|
m_player->HideViewModels(); |
|
} |
|
} |
|
|
|
// We must update our state |
|
m_bForceUpdate = true; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose: Samples the player's inputs and fires outputs based on what buttons |
|
// are currently held down. |
|
//------------------------------------------------------------------------------ |
|
void CGameUI::Think( void ) |
|
{ |
|
CBasePlayer *pPlayer = m_player; |
|
|
|
// If player is gone, stop thinking |
|
if (pPlayer == NULL) |
|
{ |
|
SetNextThink( TICK_NEVER_THINK ); |
|
return; |
|
} |
|
|
|
// If we're forcing an update, state with a clean button state |
|
if ( m_bForceUpdate ) |
|
{ |
|
m_nLastButtonState = pPlayer->m_nButtons; |
|
} |
|
|
|
// ------------------------------------------------ |
|
// Check that toucher is facing the UI within |
|
// the field of view tolerance. If not disconnect |
|
// ------------------------------------------------ |
|
if (m_flFieldOfView > -1) |
|
{ |
|
Vector vPlayerFacing; |
|
pPlayer->EyeVectors( &vPlayerFacing ); |
|
Vector vPlayerToUI = GetAbsOrigin() - pPlayer->WorldSpaceCenter(); |
|
VectorNormalize(vPlayerToUI); |
|
|
|
float flDotPr = DotProduct(vPlayerFacing,vPlayerToUI); |
|
if (flDotPr < m_flFieldOfView) |
|
{ |
|
Deactivate( pPlayer ); |
|
return; |
|
} |
|
} |
|
|
|
pPlayer->AddFlag( FL_ONTRAIN ); |
|
SetNextThink( gpGlobals->curtime ); |
|
|
|
// Deactivate if they jump or press +use. |
|
// FIXME: prevent the use from going through in player.cpp |
|
if ((( pPlayer->m_afButtonPressed & IN_USE ) && ( m_spawnflags & SF_GAMEUI_USE_DEACTIVATES )) || |
|
(( pPlayer->m_afButtonPressed & IN_JUMP ) && ( m_spawnflags & SF_GAMEUI_JUMP_DEACTIVATES ))) |
|
{ |
|
Deactivate( pPlayer ); |
|
return; |
|
} |
|
|
|
// Determine what's different |
|
int nButtonsChanged = ( pPlayer->m_nButtons ^ m_nLastButtonState ); |
|
|
|
// |
|
// Handle all our possible input triggers |
|
// |
|
|
|
if ( nButtonsChanged & IN_MOVERIGHT ) |
|
{ |
|
if ( m_nLastButtonState & IN_MOVERIGHT ) |
|
{ |
|
m_unpressedMoveRight.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedMoveRight.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
if ( nButtonsChanged & IN_MOVELEFT ) |
|
{ |
|
if ( m_nLastButtonState & IN_MOVELEFT ) |
|
{ |
|
m_unpressedMoveLeft.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedMoveLeft.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
if ( nButtonsChanged & IN_FORWARD ) |
|
{ |
|
if ( m_nLastButtonState & IN_FORWARD ) |
|
{ |
|
m_unpressedForward.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedForward.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
if ( nButtonsChanged & IN_BACK ) |
|
{ |
|
if ( m_nLastButtonState & IN_BACK ) |
|
{ |
|
m_unpressedBack.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedBack.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
if ( nButtonsChanged & IN_ATTACK ) |
|
{ |
|
if ( m_nLastButtonState & IN_ATTACK ) |
|
{ |
|
m_unpressedAttack.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedAttack.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
if ( nButtonsChanged & IN_ATTACK2 ) |
|
{ |
|
if ( m_nLastButtonState & IN_ATTACK2 ) |
|
{ |
|
m_unpressedAttack2.FireOutput( pPlayer, this, 0 ); |
|
} |
|
else |
|
{ |
|
m_pressedAttack2.FireOutput( pPlayer, this, 0 ); |
|
} |
|
} |
|
|
|
// Setup for the next frame |
|
m_nLastButtonState = pPlayer->m_nButtons; |
|
|
|
float x = 0, y = 0, attack = 0, attack2 = 0; |
|
if ( pPlayer->m_nButtons & IN_MOVERIGHT ) |
|
{ |
|
x = 1; |
|
} |
|
else if ( pPlayer->m_nButtons & IN_MOVELEFT ) |
|
{ |
|
x = -1; |
|
} |
|
|
|
if ( pPlayer->m_nButtons & IN_FORWARD ) |
|
{ |
|
y = 1; |
|
} |
|
else if ( pPlayer->m_nButtons & IN_BACK ) |
|
{ |
|
y = -1; |
|
} |
|
|
|
if ( pPlayer->m_nButtons & IN_ATTACK ) |
|
{ |
|
attack = 1; |
|
} |
|
|
|
if ( pPlayer->m_nButtons & IN_ATTACK2 ) |
|
{ |
|
attack2 = 1; |
|
} |
|
|
|
// |
|
// Fire the analog outputs if they changed. |
|
// |
|
if ( m_bForceUpdate || ( m_xaxis.Get() != x ) ) |
|
{ |
|
m_xaxis.Set( x, pPlayer, this ); |
|
} |
|
|
|
if ( m_bForceUpdate || ( m_yaxis.Get() != y ) ) |
|
{ |
|
m_yaxis.Set( y, pPlayer, this ); |
|
} |
|
|
|
if ( m_bForceUpdate || ( m_attackaxis.Get() != attack ) ) |
|
{ |
|
m_attackaxis.Set( attack, pPlayer, this ); |
|
} |
|
|
|
if ( m_bForceUpdate || ( m_attack2axis.Get() != attack2 ) ) |
|
{ |
|
m_attack2axis.Set( attack2, pPlayer, this ); |
|
} |
|
|
|
m_bForceUpdate = false; |
|
}
|
|
|