csgo-2018-source/game/shared/portal/prop_portal_shared.cpp
2021-07-24 21:11:47 -07:00

272 lines
8.0 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "prop_portal_shared.h"
#include "portal_shareddefs.h"
#include "portal_placement.h"
#include "weapon_portalgun_shared.h"
#if defined( GAME_DLL )
#include "baseprojector.h"
#else
#include "c_baseprojectedentity.h"
typedef C_BaseProjectedEntity CBaseProjectedEntity;
#endif
CUtlVector<CProp_Portal *> CProp_Portal_Shared::AllPortals;
extern ConVar sv_portal_placement_never_fail;
void CProp_Portal::PlacePortal( const Vector &vOrigin, const QAngle &qAngles, PortalPlacementResult_t eResult, bool bDelay /*= false*/ )
{
Vector vOldOrigin = GetLocalOrigin();
QAngle qOldAngles = GetLocalAngles();
Vector vNewOrigin = vOrigin;
QAngle qNewAngles = qAngles;
#if !defined( PORTAL2 )
UTIL_TestForOrientationVolumes( qNewAngles, vNewOrigin, this );
#endif // PORTAL2
if ( PortalPlacementSucceeded( eResult ) == false && sv_portal_placement_never_fail.GetBool() == false )
{
// Prepare fizzle
m_vDelayedPosition = vOrigin;
m_qDelayedAngles = qAngles;
// Translate the fizzle type
// FIXME: This can go away, we don't care about the fizzle type anymore -- jdw
switch( eResult )
{
case PORTAL_PLACEMENT_CANT_FIT:
m_iDelayedFailure = PORTAL_FIZZLE_CANT_FIT;
break;
case PORTAL_PLACEMENT_OVERLAP_LINKED:
m_iDelayedFailure = PORTAL_FIZZLE_OVERLAPPED_LINKED;
break;
case PORTAL_PLACEMENT_INVALID_VOLUME:
m_iDelayedFailure = PORTAL_FIZZLE_BAD_VOLUME;
break;
case PORTAL_PLACEMENT_INVALID_SURFACE:
m_iDelayedFailure = PORTAL_FIZZLE_BAD_SURFACE;
break;
case PORTAL_PLACEMENT_CLEANSER:
m_iDelayedFailure = PORTAL_FIZZLE_CLEANSER;
break;
default:
case PORTAL_PLACEMENT_PASSTHROUGH_SURFACE:
m_iDelayedFailure = PORTAL_FIZZLE_NONE;
break;
}
return;
}
m_vDelayedPosition = vNewOrigin;
m_qDelayedAngles = qNewAngles;
m_iDelayedFailure = PORTAL_FIZZLE_SUCCESS;
if ( bDelay == false )
{
NewLocation( vNewOrigin, qNewAngles );
}
}
//-----------------------------------------------------------------------------
// Purpose: Runs when a fired portal shot reaches it's destination wall. Detects current placement valididty state.
//-----------------------------------------------------------------------------
void CProp_Portal::DelayedPlacementThink( void )
{
Vector vOldOrigin = m_ptOrigin; //GetLocalOrigin();
QAngle qOldAngles = m_qAbsAngle; //GetLocalAngles();
Vector vForward;
AngleVectors( m_qDelayedAngles, &vForward );
// Check if something made the spot invalid mid flight
// Bad surface and near fizzle effects take priority
if ( m_iDelayedFailure != PORTAL_FIZZLE_BAD_SURFACE && m_iDelayedFailure != PORTAL_FIZZLE_NEAR_BLUE && m_iDelayedFailure != PORTAL_FIZZLE_NEAR_RED )
{
if ( IsPortalOverlappingOtherPortals( this, m_vDelayedPosition, m_qDelayedAngles, GetHalfWidth(), GetHalfHeight() ) )
{
m_iDelayedFailure = PORTAL_FIZZLE_OVERLAPPED_LINKED;
}
else if ( IsPortalIntersectingNoPortalVolume( m_vDelayedPosition, m_qDelayedAngles, vForward, GetHalfWidth(), GetHalfHeight() ) )
{
#if defined GAME_DLL
RANDOM_CEG_TEST_SECRET_PERIOD( 29, 83 )
#endif
m_iDelayedFailure = PORTAL_FIZZLE_BAD_VOLUME;
}
}
if ( sv_portal_placement_never_fail.GetBool() )
{
m_iDelayedFailure = PORTAL_FIZZLE_SUCCESS;
}
DoFizzleEffect( m_iDelayedFailure );
if ( m_iDelayedFailure != PORTAL_FIZZLE_SUCCESS )
{
// It didn't successfully place
return;
}
// Do effects at old location if it was active
if ( GetOldActiveState() )
{
DoFizzleEffect( PORTAL_FIZZLE_CLOSE, false );
}
#if defined( GAME_DLL )
CWeaponPortalgun *pPortalGun = dynamic_cast<CWeaponPortalgun*>( m_hPlacedBy.Get() );
if( pPortalGun )
{
CPortal_Player *pFiringPlayer = dynamic_cast<CPortal_Player *>( pPortalGun->GetOwner() );
if( pFiringPlayer )
{
pFiringPlayer->IncrementPortalsPlaced( IsPortal2() );
// Placement successful, fire the output
m_OnPlacedSuccessfully.FireOutput( pPortalGun, this );
}
}
#endif
// Move to new location
NewLocation( m_vDelayedPosition, m_qDelayedAngles );
#if defined( GAME_DLL )
// Test for our surface moving out from behind us
SetContextThink( &CProp_Portal::TestRestingSurfaceThink, gpGlobals->curtime + 0.1f, s_szTestRestingSurfaceThinkContext );
CBaseProjector::TestAllForProjectionChanges();
#else
CBaseProjectedEntity::TestAllForProjectionChanges();
#endif
}
// default to sane-looking but incorrect portal height for CEG - Updated in constructor
bool CProp_Portal::ms_DefaultPortalSizeInitialized = false; // for CEG protection
float CProp_Portal::ms_DefaultPortalHalfWidth = DEFAULT_PORTAL_HALF_WIDTH;
float CProp_Portal::ms_DefaultPortalHalfHeight = 0.25 * DEFAULT_PORTAL_HALF_HEIGHT;
//NULL portal will return default width/height
void CProp_Portal::GetPortalSize( float &fHalfWidth, float &fHalfHeight, CProp_Portal *pPortal )
{
if( pPortal )
{
fHalfWidth = pPortal->GetHalfWidth();
fHalfHeight = pPortal->GetHalfHeight();
}
else
{
fHalfWidth = ms_DefaultPortalHalfWidth;
fHalfHeight = ms_DefaultPortalHalfHeight;
}
}
void CProp_Portal::SetFiredByPlayer( CBasePlayer *pPlayer )
{
m_hFiredByPlayer = pPlayer;
if( pPlayer )
{
SetPlayerSimulated( pPlayer );
}
else
{
UnsetPlayerSimulated();
}
}
extern ConVar sv_gravity;
float CProp_Portal::GetMinimumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity )
{
if( bExitOnFloor )
{
if( bPlayer )
{
return 300.0f;
}
else
{
return bEntranceOnFloor ? 225.0f : 50.0f;
}
}
else if( bPlayer )
{
//bExitOnFloor means the portal is facing almost entirely up, just because it's false doesn't mean the portal isn't facing significantly up
//We also need to solve the case where the player's AABB rotates in such a way that we pull the ground out from under them
if( m_vForward.z > 0.5f ) //forward facing up by at least 30 degrees
{
float fGravity = GetGravity();
if ( fGravity != 0.0f )
{
fGravity *= sv_gravity.GetFloat();
}
else
{
fGravity = sv_gravity.GetFloat();
}
if( fGravity != 0.0f )
{
//Assuming our current velocity is zero. What's the minimum portal-forward velocity to perch the player on the bottom edge of the portal?
Vector vPerchPoint = m_ptOrigin - (m_vUp * GetHalfHeight()); //a point along the bottom edge of the portal, horizontally centered
Vector vPlayerExtents = (((CPortal_Player *)pEntity)->GetHullMaxs() - ((CPortal_Player *)pEntity)->GetHullMins()) * 0.5f;
//Vector vPlayerCenterToPerch = vPerchPoint - vEntityCenterAtExit;
Vector vTestBBoxPoint = vEntityCenterAtExit;
//vTestBBoxPoint.x += Sign( vPlayerCenterToPerch.x ) * vPlayerExtents.x;
//vTestBBoxPoint.y += Sign( vPlayerCenterToPerch.y ) * vPlayerExtents.y;
vTestBBoxPoint.z -= vPlayerExtents.z;
Vector vTestToPerch = vPerchPoint - vTestBBoxPoint;
vTestToPerch -= vTestToPerch.Dot( m_vRight ) * m_vRight; //Project test vector onto horizontal center, so all x/y dist to perch point is actually distance to perch line
float fHorzTestToPerch = vTestToPerch.Length2D();
float fHorzVelocityComponent = m_vForward.Length2D(); //the portion of our velocity axis that will move us horizontally toward the perch
float fRoot1, fRoot2;
if( SolveQuadratic( (m_vForward.z * (-2.0f)) * ((fHorzTestToPerch * fHorzVelocityComponent) - (vTestToPerch.z*m_vForward.z)), 0, fHorzTestToPerch * fHorzTestToPerch * fGravity, fRoot1, fRoot2 ) )
{
float fMax = MAX( fRoot1, fRoot2 );
if( fMax > 0.0f )
{
if( fMax > 300.0f ) //cap out at floor/floor minimum
return 300.0f;
else
return fMax;
}
}
}
}
}
return BaseClass::GetMinimumExitSpeed( bPlayer, bEntranceOnFloor, bExitOnFloor, vEntityCenterAtExit, pEntity );
}
float CProp_Portal::GetMaximumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity )
{
return 1000.0f;
}