diff --git a/game/client/episodic/c_vort_charge_token.cpp b/game/client/episodic/c_vort_charge_token.cpp index fa769fa0..9c6e0986 100644 --- a/game/client/episodic/c_vort_charge_token.cpp +++ b/game/client/episodic/c_vort_charge_token.cpp @@ -261,8 +261,11 @@ void C_VortigauntChargeToken::NotifyShouldTransmit( ShouldTransmitState_t state // Turn on if ( state == SHOULDTRANSMIT_START ) { - m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW ); - m_hEffect->SetControlPointEntity( 0, this ); + if ( m_hEffect ) + { + m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW ); + m_hEffect->SetControlPointEntity( 0, this ); + } } } @@ -392,8 +395,11 @@ void C_VortigauntEffectDispel::NotifyShouldTransmit( ShouldTransmitState_t state // Turn on if ( state == SHOULDTRANSMIT_START ) { + if( m_hEffect ) + { m_hEffect = ParticleProp()->Create( "vortigaunt_hand_glow", PATTACH_ABSORIGIN_FOLLOW ); - m_hEffect->SetControlPointEntity( 0, this ); + m_hEffect->SetControlPointEntity( 0, this ); + } } } diff --git a/game/server/physics_prop_ragdoll.cpp b/game/server/physics_prop_ragdoll.cpp index 72635ea8..f2b1998f 100644 --- a/game/server/physics_prop_ragdoll.cpp +++ b/game/server/physics_prop_ragdoll.cpp @@ -1509,6 +1509,9 @@ void CRagdollPropAttached::InitRagdollAttached( IPhysicsObject *pRefObject = m_ragdoll.list[ragdollAttachedIndex].pObject; + if( !pRefObject ) + return; + Vector attachmentPointRagdollSpace; pRefObject->WorldToLocal( &attachmentPointRagdollSpace, worldAttachOrigin ); diff --git a/game/server/portal/portal_placement.cpp b/game/server/portal/portal_placement.cpp index 1a5dcef5..8850136f 100644 --- a/game/server/portal/portal_placement.cpp +++ b/game/server/portal/portal_placement.cpp @@ -34,7 +34,7 @@ bool g_bBumpedByLinkedPortal; ConVar sv_portal_placement_debug ("sv_portal_placement_debug", "0", FCVAR_REPLICATED ); ConVar sv_portal_placement_never_bump ("sv_portal_placement_never_bump", "0", FCVAR_REPLICATED | FCVAR_CHEAT ); - +extern ConVar sv_allow_mobile_portals; bool IsMaterialInList( const csurface_t &surface, char *g_ppszMaterials[] ) { @@ -1188,22 +1188,7 @@ float VerifyPortalPlacement( const CProp_Portal *pIgnorePortal, Vector &vOrigin, return PORTAL_ANALOG_SUCCESS_INVALID_SURFACE; } - // Check if the surface is moving - Vector vVelocityCheck; - AngularImpulse vAngularImpulseCheck; - - IPhysicsObject *pPhysicsObject = tr.m_pEnt->VPhysicsGetObject(); - - if ( pPhysicsObject ) - { - pPhysicsObject->GetVelocity( &vVelocityCheck, &vAngularImpulseCheck ); - } - else - { - tr.m_pEnt->GetVelocity( &vVelocityCheck, &vAngularImpulseCheck ); - } - - if ( vVelocityCheck != vec3_origin || vAngularImpulseCheck != vec3_origin ) + if ( !sv_allow_mobile_portals.GetBool() && UTIL_IsEntityMovingOrRotating( tr.m_pEnt )/*(vVelocityCheck != vec3_origin || vAngularImpulseCheck != vec3_origin)*/ ) { if ( sv_portal_placement_debug.GetBool() ) { diff --git a/game/server/portal/prop_portal.cpp b/game/server/portal/prop_portal.cpp index ffa196d8..61a2aac8 100644 --- a/game/server/portal/prop_portal.cpp +++ b/game/server/portal/prop_portal.cpp @@ -1371,7 +1371,7 @@ void CProp_Portal::Touch( CBaseEntity *pOther ) DoFizzleEffect( PORTAL_FIZZLE_KILLED, false ); Fizzle(); } - else if ( tr.m_pEnt && tr.m_pEnt->IsMoving() ) + else if ( !sv_allow_mobile_portals.GetBool() && tr.m_pEnt && tr.m_pEnt->IsMoving() ) { DevMsg( "Surface behind portal is moving.\n" ); diff --git a/game/server/portal/prop_portal.h b/game/server/portal/prop_portal.h index ce181193..966273af 100644 --- a/game/server/portal/prop_portal.h +++ b/game/server/portal/prop_portal.h @@ -162,5 +162,6 @@ inline const VMatrix& CProp_Portal::MatrixThisToLinked() const return m_matrixThisToLinked; } +extern ConVar sv_allow_mobile_portals; #endif //#ifndef PROP_PORTAL_H diff --git a/game/server/portal/weapon_portalgun.cpp b/game/server/portal/weapon_portalgun.cpp index c6bab7d1..b08d502d 100644 --- a/game/server/portal/weapon_portalgun.cpp +++ b/game/server/portal/weapon_portalgun.cpp @@ -402,7 +402,7 @@ float CWeaponPortalgun::TraceFirePortal( bool bPortal2, const Vector &vTraceStar qFinalAngles = pPortal->m_qDelayedAngles; } - return PORTAL_ANALOG_SUCCESS_BUMPED; + return PORTAL_ANALOG_SUCCESS_PASSTHROUGH_SURFACE; } // Trace to the surface to see if there's a rotating door in the way diff --git a/game/shared/gamemovement.cpp b/game/shared/gamemovement.cpp index 6258459a..8d351ef7 100644 --- a/game/shared/gamemovement.cpp +++ b/game/shared/gamemovement.cpp @@ -34,7 +34,7 @@ extern IFileSystem *filesystem; #include "env_player_surface_trigger.h" static ConVar dispcoll_drawplane( "dispcoll_drawplane", "0" ); #endif - +static ConVar sv_autojump_( "sv_autojump_", "0" ); // tickcount currently isn't set during prediction, although gpGlobals->curtime and // gpGlobals->frametime are. We should probably set tickcount (to player->m_nTickBase), @@ -2347,7 +2347,6 @@ void CGameMovement::PlaySwimSound() MoveHelper()->StartSound( mv->GetAbsOrigin(), "Player.Swim" ); } - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -2404,8 +2403,11 @@ bool CGameMovement::CheckJumpButton( void ) return false; #endif - if ( mv->m_nOldButtons & IN_JUMP ) + if ( (mv->m_nOldButtons & IN_JUMP) && + (!sv_autojump_.GetBool() && player->GetGroundEntity()) ) + { return false; // don't pogo stick + } // Cannot jump will in the unduck transition. if ( player->m_Local.m_bDucking && ( player->GetFlags() & FL_DUCKING ) ) @@ -2526,6 +2528,7 @@ bool CGameMovement::CheckJumpButton( void ) // Flag that we jumped. mv->m_nOldButtons |= IN_JUMP; // don't jump again until released + return true; } diff --git a/game/shared/portal/PortalSimulation.cpp b/game/shared/portal/PortalSimulation.cpp index d20f56d6..ddf2befd 100644 --- a/game/shared/portal/PortalSimulation.cpp +++ b/game/shared/portal/PortalSimulation.cpp @@ -8,6 +8,7 @@ #include "cbase.h" #include "PortalSimulation.h" +#include "convar.h" #include "vphysics_interface.h" #include "physics.h" #include "portal_shareddefs.h" @@ -16,6 +17,7 @@ #include "filesystem.h" #include "collisionutils.h" #include "tier1/callqueue.h" +#include "vphysics/virtualmesh.h" #ifndef CLIENT_DLL @@ -44,6 +46,7 @@ extern IPhysicsConstraintEvent *g_pConstraintEvents; static ConVar sv_portal_collision_sim_bounds_x( "sv_portal_collision_sim_bounds_x", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" ); static ConVar sv_portal_collision_sim_bounds_y( "sv_portal_collision_sim_bounds_y", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" ); static ConVar sv_portal_collision_sim_bounds_z( "sv_portal_collision_sim_bounds_z", "252", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" ); +ConVar portal_clone_displacements ( "portal_clone_displacements", "1", FCVAR_REPLICATED | FCVAR_CHEAT ); //#define DEBUG_PORTAL_SIMULATION_CREATION_TIMES //define to output creation timings to developer 2 //#define DEBUG_PORTAL_COLLISION_ENVIRONMENTS //define this to allow for glview collision dumps of portal simulators @@ -1208,6 +1211,19 @@ void CPortalSimulator::CreateLocalPhysics( void ) m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class } + if( m_InternalData.Simulation.Static.World.Displacements.pCollideable != NULL ) + { + m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.World.Displacements.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, ¶ms ); + + if( (m_InternalData.Simulation.pCollisionEntity != NULL) && (m_InternalData.Simulation.pCollisionEntity->VPhysicsGetObject() == NULL) ) + { + m_InternalData.Simulation.pCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject); + m_InternalData.Simulation.pCollisionEntity = NULL; + } + + m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class + } + //Assert( m_InternalData.Simulation.Static.World.StaticProps.PhysicsObjects.Count() == 0 ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation #ifdef _DEBUG for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; ) @@ -1435,12 +1451,20 @@ void CPortalSimulator::ClearLocalPhysics( void ) m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList(); m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( true ); //if we don't do this, things crash the next time we cleanup the delete list while checking mindists + //world brushes if( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject ) { m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject ); m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject = NULL; } + //world displacement surfaces + if( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject ) + { + m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject ); + m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = NULL; + } + if( m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists && (m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) ) { @@ -1646,6 +1670,181 @@ bool CPortalSimulator::CreateLocalCollision( void ) STOPDEBUGTIMER( worldBrushTimer ); DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldBrushTimer.GetDuration().GetMillisecondsF() ); ); + // Displacements + if ( portal_clone_displacements.GetBool() ) + { + //scale the extents to usable sizes + float flScaleX = sv_portal_collision_sim_bounds_x.GetFloat(); + if ( flScaleX < 200.0f ) + flScaleX = 200.0f; + float flScaleY = sv_portal_collision_sim_bounds_y.GetFloat(); + if ( flScaleY < 200.0f ) + flScaleY = 200.0f; + float flScaleZ = sv_portal_collision_sim_bounds_z.GetFloat(); + if ( flScaleZ < 252.0f ) + flScaleZ = 252.0f; + + VPlane displacementRejectRegions[6]; + displacementRejectRegions[0].m_Normal = -m_InternalData.Placement.vForward; + displacementRejectRegions[0].m_Dist = displacementRejectRegions[0].m_Normal.Dot( m_InternalData.Placement.ptCenter ); + displacementRejectRegions[1].m_Normal = m_InternalData.Placement.vForward; + displacementRejectRegions[1].m_Dist = displacementRejectRegions[1].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleX; + displacementRejectRegions[2].m_Normal = m_InternalData.Placement.vRight; + displacementRejectRegions[2].m_Dist = displacementRejectRegions[2].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleY; + displacementRejectRegions[3].m_Normal = -m_InternalData.Placement.vRight; + displacementRejectRegions[3].m_Dist = displacementRejectRegions[3].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleY; + displacementRejectRegions[4].m_Normal = m_InternalData.Placement.vUp; + displacementRejectRegions[4].m_Dist = displacementRejectRegions[4].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleZ; + displacementRejectRegions[5].m_Normal = -m_InternalData.Placement.vUp; + displacementRejectRegions[5].m_Dist = displacementRejectRegions[5].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleZ; + + CREATEDEBUGTIMER( dispTimer ); + STARTDEBUGTIMER( dispTimer ); + Assert( m_InternalData.Simulation.Static.World.Displacements.pCollideable == NULL ); + virtualmeshlist_t DisplacementMeshes[32]; + + int iMeshes = enginetrace->GetMeshesFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs, DisplacementMeshes, ARRAYSIZE(DisplacementMeshes) ); + if( iMeshes > 0 ) + { + CPhysPolysoup *pDispCollideSoup = physcollision->PolysoupCreate(); + + // Count total triangles added to this poly soup- Can't support more than 65535. + int iTriCount = 0; + + for( int i = 0; (i != iMeshes) && (iTriCount < 65535); ++i ) + { + virtualmeshlist_t *pMesh = &DisplacementMeshes[i]; + + for ( int j = 0; j < pMesh->indexCount; j+=3 ) + { + Vector *points[3] = { &pMesh->pVerts[ pMesh->indices[j+0] ], &pMesh->pVerts[ pMesh->indices[j+1] ], &pMesh->pVerts[ pMesh->indices[j+2] ] }; + + //test for triangles that lie completely outside our collision area + { + int k; + for( k = 0; k != ARRAYSIZE( displacementRejectRegions ); ++k ) + { + //test all 3 points on each plane + if( (displacementRejectRegions[k].DistTo( *points[0] ) >= 0.0f) && + (displacementRejectRegions[k].DistTo( *points[1] ) >= 0.0f) && + (displacementRejectRegions[k].DistTo( *points[2] ) >= 0.0f) ) + { + break; //break out if all 3 are in front of a rejection plane + } + } + + if( k != ARRAYSIZE( displacementRejectRegions ) ) + { + //was fully rejected by a plane + continue; + } + } + + //clip to portal plane + { + //we do however need to clip to the wall plane + int iFront = 0; + int iBack = 0; + float fDists[3]; + int iForwardPoints[3]; + int iBackPoints[3]; + for( int k = 0; k != 3; ++k ) + { + fDists[k] = m_InternalData.Placement.PortalPlane.DistTo( *points[k] ); + if( fDists[k] >= 0.0f ) + { + iForwardPoints[iFront] = k; + ++iFront; + } + else + { + iBackPoints[iBack] = k; + ++iBack; + } + } + if( iFront != 0 ) + { + if( iBack != 0 ) + { + //need to clip the triangle + Vector vClippedPoints[2]; //guaranteed to intersect exactly twice + + if( iBack == 2 ) + { + if( fDists[iForwardPoints[0]] < 0.1f ) + continue; + + //easy case. + float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]]; + if( fTotalDist < 0.1f ) + continue; + + vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist)); + points[iBackPoints[0]] = &vClippedPoints[0]; + + fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[1]]; + if( fTotalDist < 0.1f ) + continue; + + vClippedPoints[1] = ((*points[iBackPoints[1]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[1]]/fTotalDist)); + points[iBackPoints[1]] = &vClippedPoints[1]; + + physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex ); + ++iTriCount; + } + else + { + if( fDists[iBackPoints[0]] > -0.1f ) + { + physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex ); + ++iTriCount; + continue; + } + + //need to create 2 triangles + float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]]; + vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist)); + fTotalDist = fDists[iForwardPoints[1]] - fDists[iBackPoints[0]]; + vClippedPoints[1] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[1]]/fTotalDist)) - ((*points[iForwardPoints[1]]) * (fDists[iBackPoints[0]]/fTotalDist)); + + points[iBackPoints[0]] = &vClippedPoints[0]; + physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex ); + ++iTriCount; + + points[iBackPoints[0]] = &vClippedPoints[1]; + points[iForwardPoints[0]] = &vClippedPoints[0]; + physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex ); + ++iTriCount; + } + } + else + { + //triangle resides wholly in front of the portal plane + physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex ); + ++iTriCount; + } + + if( iTriCount >= 65535 ) + { + break; + } + } + } + + }// triangle loop + } + + m_InternalData.Simulation.Static.World.Displacements.pCollideable = physcollision->ConvertPolysoupToCollide( pDispCollideSoup, false ); + + // clean up poly soup + physcollision->PolysoupDestroy( pDispCollideSoup ); + } + + //m_InternalData.Simulation.Static.World.Displacements.pCollideable = enginetrace->GetCollidableFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs ); + STOPDEBUGTIMER( dispTimer ); + DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sDisplacement Surfaces=%fms\n", GetPortalSimulatorGUID(), TABSPACING, dispTimer.GetDuration().GetMillisecondsF() ); ); + } + CREATEDEBUGTIMER( worldPropTimer ); STARTDEBUGTIMER( worldPropTimer ); #ifdef _DEBUG @@ -1806,6 +2005,12 @@ void CPortalSimulator::ClearLocalCollision( void ) m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable = NULL; } + if( m_InternalData.Simulation.Static.World.Displacements.pCollideable ) + { + physcollision->DestroyCollide( m_InternalData.Simulation.Static.World.Displacements.pCollideable ); + m_InternalData.Simulation.Static.World.Displacements.pCollideable = NULL; + } + if( m_InternalData.Simulation.Static.World.Brushes.pCollideable ) { physcollision->DestroyCollide( m_InternalData.Simulation.Static.World.Brushes.pCollideable ); @@ -1919,6 +2124,9 @@ void CPortalSimulator::CreatePolyhedrons( void ) if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z; } + m_InternalData.Placement.vecCurAABBMins = vAABBMins; + m_InternalData.Placement.vecCurAABBMaxs = vAABBMaxs; + //Brushes { Assert( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() == 0 ); @@ -2413,7 +2621,7 @@ void CPortalSimulator::PrePhysFrame( void ) Assert( (pEntity != NULL) && (pEntity->IsMarkedForDeletion() == false) ); IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); - if( (pPhysObject == NULL) || pPhysObject->IsAsleep() ) + if( pPhysObject == NULL /*|| pPhysObject->IsAsleep() */) continue; int iEntIndex = pEntity->entindex(); @@ -2572,7 +2780,15 @@ bool CPortalSimulator::CreatedPhysicsObject( const IPhysicsObject *pObject, PS_P *pOut_SourceType = PSPOST_HOLYWALL_TUBE; return true; - } + } + + if( pObject == m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject ) + { + if( pOut_SourceType ) + *pOut_SourceType = PSPOST_LOCAL_DISPLACEMENT; + + return true; + } return false; } @@ -2980,6 +3196,14 @@ int CPSCollisionEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listM return iRetVal; } + if( m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Displacements.pPhysicsObject != NULL ) + { + pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Displacements.pPhysicsObject; + ++iRetVal; + if( iRetVal == listMax ) + return iRetVal; + } + return iRetVal; } @@ -3028,6 +3252,9 @@ void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char * } } + if ( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable ) + PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName ); + if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable ) PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName ); diff --git a/game/shared/portal/PortalSimulation.h b/game/shared/portal/PortalSimulation.h index 9af361e6..90dda429 100644 --- a/game/shared/portal/PortalSimulation.h +++ b/game/shared/portal/PortalSimulation.h @@ -40,7 +40,8 @@ enum PS_PhysicsObjectSourceType_t PSPOST_REMOTE_BRUSHES, PSPOST_LOCAL_STATICPROPS, PSPOST_REMOTE_STATICPROPS, - PSPOST_HOLYWALL_TUBE + PSPOST_HOLYWALL_TUBE, + PSPOST_LOCAL_DISPLACEMENT }; struct PortalTransformAsAngledPosition_t //a matrix transformation from this portal to the linked portal, stored as vector and angle transforms @@ -105,6 +106,8 @@ struct PS_PlacementData_t //stuff useful for geometric operations PortalTransformAsAngledPosition_t ptaap_ThisToLinked; PortalTransformAsAngledPosition_t ptaap_LinkedToThis; CPhysCollide *pHoleShapeCollideable; //used to test if a collideable is in the hole, should NOT be collided against in general + Vector vecCurAABBMins; + Vector vecCurAABBMaxs; PS_PlacementData_t( void ) { memset( this, 0, sizeof( PS_PlacementData_t ) ); @@ -124,6 +127,17 @@ struct PS_SD_Static_World_Brushes_t }; +struct PS_SD_Static_World_Displacements_t +{ + CPhysCollide *pCollideable; +#ifndef CLIENT_DLL + IPhysicsObject *pPhysicsObject; + PS_SD_Static_World_Displacements_t() : pCollideable(NULL), pPhysicsObject(NULL) {}; +#else + PS_SD_Static_World_Displacements_t() : pCollideable(NULL) {}; +#endif +}; + struct PS_SD_Static_World_StaticProps_ClippedProp_t { @@ -153,6 +167,7 @@ struct PS_SD_Static_World_StaticProps_t struct PS_SD_Static_World_t //stuff in front of the portal { PS_SD_Static_World_Brushes_t Brushes; + PS_SD_Static_World_Displacements_t Displacements; PS_SD_Static_World_StaticProps_t StaticProps; }; diff --git a/game/shared/portal/portal_util_shared.cpp b/game/shared/portal/portal_util_shared.cpp index d69e7ffe..58376e21 100644 --- a/game/shared/portal/portal_util_shared.cpp +++ b/game/shared/portal/portal_util_shared.cpp @@ -35,6 +35,9 @@ ConVar sv_portal_trace_vs_holywall ("sv_portal_trace_vs_holywall", "1", FCVAR_RE ConVar sv_portal_trace_vs_staticprops ("sv_portal_trace_vs_staticprops", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Use traces against portal environment static prop geometry" ); ConVar sv_use_find_closest_passable_space ("sv_use_find_closest_passable_space", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Enables heavy-handed player teleporting stuck fix code." ); ConVar sv_use_transformed_collideables("sv_use_transformed_collideables", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Disables traces against remote portal moving entities using transforms to bring them into local space." ); + +extern ConVar portal_clone_displacements; + class CTransformedCollideable : public ICollideable //wraps an existing collideable, but transforms everything that pertains to world space by another transform { public: @@ -623,6 +626,16 @@ void UTIL_Portal_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsign bCopyBackBrushTraceData = true; } + if( portalSimulator.m_DataAccess.Simulation.Static.World.Displacements.pCollideable && sv_portal_trace_vs_world.GetBool() && portal_clone_displacements.GetBool() ) + { + physcollision->TraceBox( ray, portalSimulator.m_DataAccess.Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, &TempTrace ); + if( (TempTrace.startsolid == false) && (TempTrace.fraction < pTrace->fraction) ) //never allow something to be stuck in the tube, it's more of a last-resort guide than a real collideable + { + *pTrace = TempTrace; + bCopyBackBrushTraceData = true; + } + } + if( bTraceHolyWall ) { if( portalSimulator.m_DataAccess.Simulation.Static.Wall.Local.Tube.pCollideable ) @@ -938,6 +951,18 @@ void UTIL_Portal_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, c } } + if( pPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable && + sv_portal_trace_vs_world.GetBool() && + portal_clone_displacements.GetBool() ) + { + physcollision->TraceBox( entRay, MASK_ALL, NULL, pPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, &tempTrace ); + + if ( tempTrace.startsolid || (tempTrace.fraction < pTrace->fraction) ) + { + *pTrace = tempTrace; + } + } + //if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable && if( pLinkedPortalSimulator && pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Brushes.pCollideable && @@ -955,6 +980,20 @@ void UTIL_Portal_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, c } } + if( pLinkedPortalSimulator && + pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable && + sv_portal_trace_vs_world.GetBool() && + sv_portal_trace_vs_holywall.GetBool() && + portal_clone_displacements.GetBool() ) + { + physcollision->TraceBox( entRay, MASK_ALL, NULL, pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.ptOriginTransform, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.qAngleTransform, &tempTrace ); + + if ( tempTrace.startsolid || (tempTrace.fraction < pTrace->fraction) ) + { + *pTrace = tempTrace; + } + } + if ( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable && sv_portal_trace_vs_holywall.GetBool() ) { @@ -1717,6 +1756,58 @@ PaintPowerType UTIL_Paint_TracePower(CBaseEntity *pBrushEntity,Vector contactPoi return NO_POWER; } +bool UTIL_IsEntityMovingOrRotating( CBaseEntity* pEntity ) +{ + Vector vLinearVelocity; + AngularImpulse vAngularVelocity; + + IPhysicsObject *pEntityPhysicsObject = pEntity->VPhysicsGetObject(); +#ifdef GAME_DLL + if ( pEntityPhysicsObject ) + { + pEntityPhysicsObject->GetVelocity( &vLinearVelocity, &vAngularVelocity ); + } + else + { + pEntity->GetVelocity( &vLinearVelocity, &vAngularVelocity ); + } +#else + vLinearVelocity = pEntity->GetAbsVelocity(); + // vAngularVelocity = vec3_origin; //TODO: Find client equivalent of server code above for angular impulse + QAngleToAngularImpulse( pEntity->GetLocalAngularVelocity(), vAngularVelocity ); +#endif + + if ( pEntity->GetAbsVelocity() != vec3_origin ) + return true; + + //ugh, func_brush attached to an animating entity doesn't give the entity a velocity. Check implicit velocity + if( pEntityPhysicsObject && pEntityPhysicsObject->IsMoveable() ) + { + Vector vOtherImplicitVelocity; + pEntityPhysicsObject->GetImplicitVelocity( &vOtherImplicitVelocity, NULL ); + if( vOtherImplicitVelocity.LengthSqr() > 1e-1 ) + return true; + } + +#ifdef GAME_DLL + CBaseEntity *pCheck = pEntity; + while( pCheck ) + { + if( pCheck->GetLocalAngularVelocity() != vec3_angle ) + return true; + + pCheck = pCheck->GetParent(); + } +#endif + + // don't check for the speed, and check for position offset from when the portal is placed instead. + /*if ( vLinearVelocity.LengthSqr() > 1e-1 || vAngularVelocity.LengthSqr() > 1e-1 ) + return true;*/ + + return false; +} + + #ifdef CLIENT_DLL void UTIL_TransformInterpolatedAngle( CInterpolatedVar< QAngle > &qInterped, matrix3x4_t matTransform, bool bSkipNewest ) { diff --git a/game/shared/portal/portal_util_shared.h b/game/shared/portal/portal_util_shared.h index cb5ae4d7..ac072a2b 100644 --- a/game/shared/portal/portal_util_shared.h +++ b/game/shared/portal/portal_util_shared.h @@ -92,6 +92,7 @@ void UTIL_Portal_NDebugOverlay( const Vector &ptPortalCenter, const QAngle &qPor void UTIL_Portal_NDebugOverlay( const CProp_Portal *pPortal, int r, int g, int b, int a, bool noDepthTest, float duration ); bool FindClosestPassableSpace( CBaseEntity *pEntity, const Vector &vIndecisivePush, unsigned int fMask = MASK_SOLID ); //assumes the object is already in a mostly passable space +bool UTIL_IsEntityMovingOrRotating( CBaseEntity* pEntity ); bool UTIL_IsPaintableSurface( const csurface_t *surface ); PaintPowerType UTIL_Paint_TracePower(CBaseEntity *pBrushEntity,Vector contactPoint,Vector *vContactNormal); diff --git a/game/shared/portal/prop_portal_shared.cpp b/game/shared/portal/prop_portal_shared.cpp index f7756b21..983c922f 100644 --- a/game/shared/portal/prop_portal_shared.cpp +++ b/game/shared/portal/prop_portal_shared.cpp @@ -15,6 +15,36 @@ CUtlVector CProp_Portal_Shared::AllPortals; +void MobilePortalsUpdatedCallback( IConVar *var, const char *pOldValue, float flOldValue ); +ConVar sv_allow_mobile_portals( "sv_allow_mobile_portals", "0", FCVAR_REPLICATED, "", MobilePortalsUpdatedCallback ); + +void MobilePortalsUpdatedCallback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + if ( sv_allow_mobile_portals.GetFloat() == flOldValue ) + return; + + static ConVarRef sv_cheats ( "sv_cheats" ); + bool bCheatsAllowed = (sv_cheats.IsValid() && sv_cheats.GetBool() ); + + if ( !bCheatsAllowed ) + { +#ifdef CLIENT_DLL + DevMsg( engine->GetLevelName() ); + if ( V_stricmp( engine->GetLevelName(), "sp_a2_bts5" ) == 0 ) +#else + if ( V_stricmp( gpGlobals->mapname.ToCStr(), "sp_a2_bts5" ) == 0 ) +#endif + { + bCheatsAllowed = true; + } + } + + if ( !bCheatsAllowed ) + { + var->SetValue( 0 ); + } +} + const Vector CProp_Portal_Shared::vLocalMins( 0.0f, -PORTAL_HALF_WIDTH, -PORTAL_HALF_HEIGHT ); const Vector CProp_Portal_Shared::vLocalMaxs( 64.0f, PORTAL_HALF_WIDTH, PORTAL_HALF_HEIGHT );