void CPortalGameMovement::FunnelIntoPortal( CProp_Portal *pPortal, Vector &wishdir ) { // Make sure there's a portal if ( !pPortal ) return; // Get portal vectors Vector vPortalForward, vPortalRight, vPortalUp; pPortal->GetVectors( &vPortalForward, &vPortalRight, &vPortalUp ); // Make sure it's a floor portal if ( vPortalForward.z < 0.8f ) return; vPortalRight.z = 0.0f; vPortalUp.z = 0.0f; VectorNormalize( vPortalRight ); VectorNormalize( vPortalUp ); // Make sure the player is looking downward CPortal_Player *pPlayer = GetPortalPlayer(); Vector vPlayerForward; pPlayer->EyeVectors( &vPlayerForward ); if ( vPlayerForward.z > -0.1f ) return; Vector vPlayerOrigin = pPlayer->GetAbsOrigin(); Vector vPlayerToPortal = pPortal->GetAbsOrigin() - vPlayerOrigin; // Make sure the player is trying to air control, they're falling downward and they are vertically close to the portal if ( fabsf( wishdir[ 0 ] ) > 64.0f || fabsf( wishdir[ 1 ] ) > 64.0f || mv->m_vecVelocity[ 2 ] > -165.0f || vPlayerToPortal.z < -512.0f ) return; // Make sure we're in the 2D portal rectangle if ( ( vPlayerToPortal.Dot( vPortalRight ) * vPortalRight ).Length() > PORTAL_HALF_WIDTH * 1.5f ) return; if ( ( vPlayerToPortal.Dot( vPortalUp ) * vPortalUp ).Length() > PORTAL_HALF_HEIGHT * 1.5f ) return; if ( vPlayerToPortal.z > -8.0f ) { // We're too close the the portal to continue correcting, but zero the velocity so our fling velocity is nice mv->m_vecVelocity[ 0 ] = 0.0f; mv->m_vecVelocity[ 1 ] = 0.0f; } else { // Funnel toward the portal float fFunnelX = vPlayerToPortal.x * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 0 ]; float fFunnelY = vPlayerToPortal.y * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 1 ]; wishdir[ 0 ] += fFunnelX; wishdir[ 1 ] += fFunnelY; } }
float CWeaponPortalgun::FirePortal( bool bPortal2, Vector *pVector /*= 0*/, bool bTest /*= false*/ ) { bool bPlayer = false; Vector vEye; Vector vDirection; Vector vTracerOrigin; CBaseEntity *pOwner = GetOwner(); if ( pOwner && pOwner->IsPlayer() ) { bPlayer = true; } if( bPlayer ) { CPortal_Player *pPlayer = (CPortal_Player *)pOwner; if ( !bTest && pPlayer ) { pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY, 0 ); } Vector forward, right, up; AngleVectors( pPlayer->EyeAngles(), &forward, &right, &up ); pPlayer->EyeVectors( &vDirection, NULL, NULL ); vEye = pPlayer->EyePosition(); // Check if the players eye is behind the portal they're in and translate it VMatrix matThisToLinked; CProp_Portal *pPlayerPortal = pPlayer->m_hPortalEnvironment; if ( pPlayerPortal ) { Vector ptPortalCenter; Vector vPortalForward; ptPortalCenter = pPlayerPortal->GetAbsOrigin(); pPlayerPortal->GetVectors( &vPortalForward, NULL, NULL ); Vector vEyeToPortalCenter = ptPortalCenter - vEye; float fPortalDist = vPortalForward.Dot( vEyeToPortalCenter ); if( fPortalDist > 0.0f ) { // Eye is behind the portal matThisToLinked = pPlayerPortal->MatrixThisToLinked(); } else { pPlayerPortal = NULL; } } if ( pPlayerPortal ) { UTIL_Portal_VectorTransform( matThisToLinked, forward, forward ); UTIL_Portal_VectorTransform( matThisToLinked, right, right ); UTIL_Portal_VectorTransform( matThisToLinked, up, up ); UTIL_Portal_VectorTransform( matThisToLinked, vDirection, vDirection ); UTIL_Portal_PointTransform( matThisToLinked, vEye, vEye ); if ( pVector ) { UTIL_Portal_VectorTransform( matThisToLinked, *pVector, *pVector ); } } vTracerOrigin = vEye + forward * 30.0f + right * 4.0f + up * (-5.0f); } else { // This portalgun is not held by the player-- Fire using the muzzle attachment Vector vecShootOrigin; QAngle angShootDir; GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir ); vEye = vecShootOrigin; vTracerOrigin = vecShootOrigin; AngleVectors( angShootDir, &vDirection, NULL, NULL ); } if ( !bTest ) { SendWeaponAnim( ACT_VM_PRIMARYATTACK ); } if ( pVector ) { vDirection = *pVector; } Vector vTraceStart = vEye + (vDirection * m_fMinRange1); Vector vFinalPosition; QAngle qFinalAngles; PortalPlacedByType ePlacedBy = ( bPlayer ) ? ( PORTAL_PLACED_BY_PLAYER ) : ( PORTAL_PLACED_BY_PEDESTAL ); trace_t tr; float fPlacementSuccess = TraceFirePortal( bPortal2, vTraceStart, vDirection, tr, vFinalPosition, qFinalAngles, ePlacedBy, bTest ); if ( sv_portal_placement_never_fail.GetBool() ) { fPlacementSuccess = 1.0f; } if ( !bTest ) { CProp_Portal *pPortal = CProp_Portal::FindPortal( m_iPortalLinkageGroupID, bPortal2, true ); // If it was a failure, put the effect at exactly where the player shot instead of where the portal bumped to if ( fPlacementSuccess < 0.5f ) vFinalPosition = tr.endpos; pPortal->PlacePortal( vFinalPosition, qFinalAngles, fPlacementSuccess, true ); float fDelay = vTracerOrigin.DistTo( tr.endpos ) / ( ( bPlayer ) ? ( BLAST_SPEED ) : ( BLAST_SPEED_NON_PLAYER ) ); QAngle qFireAngles; VectorAngles( vDirection, qFireAngles ); DoEffectBlast( pPortal->m_bIsPortal2, ePlacedBy, vTracerOrigin, vFinalPosition, qFireAngles, fDelay ); pPortal->SetContextThink( &CProp_Portal::DelayedPlacementThink, gpGlobals->curtime + fDelay, s_pDelayedPlacementContext ); pPortal->m_vDelayedPosition = vFinalPosition; pPortal->m_hPlacedBy = this; } return fPlacementSuccess; }