//----------------------------------------------------------------------------- // Purpose: Target doesn't exist or has eluded us, so search for one //----------------------------------------------------------------------------- void CNPC_Portal_FloorTurret::SearchThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_SEARCHING ) ) return; SetNextThink( gpGlobals->curtime + 0.05f ); SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); //If our enemy has died, pick a new enemy if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) ) { SetEnemy( NULL ); } //Acquire the target if ( GetEnemy() == NULL ) { HackFindEnemy(); } LaserOn(); CBaseEntity *pEnemy = GetEnemy(); //If we've found a target, spin up the barrel and start to attack if ( pEnemy != NULL ) { //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = pEnemy->BodyTarget( vecMid ); //Look for our current enemy bool bEnemyInFOV = FInViewCone( pEnemy ); bool bEnemyVisible = FVisible( pEnemy ); //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); // If the enemy isn't in the normal fov, check the fov through portals CProp_Portal *pPortal = NULL; pPortal = FInViewConeThroughPortal( pEnemy ); if ( pPortal && FVisibleThroughPortal( pPortal, pEnemy ) ) { // Translate our target across the portal Vector vecMidEnemyTransformed; UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vecMidEnemy, vecMidEnemyTransformed ); //Calculate dir and dist to enemy Vector vecDirToEnemyTransformed = vecMidEnemyTransformed - vecMid; float flDistToEnemyTransformed = VectorNormalize( vecDirToEnemyTransformed ); // If it's not visible through normal means or the enemy is closer through the portal, use the translated info if ( !bEnemyInFOV || !bEnemyVisible || flDistToEnemyTransformed < m_flDistToEnemy ) { bEnemyInFOV = true; bEnemyVisible = true; vecMidEnemy = vecMidEnemyTransformed; vecDirToEnemy = vecDirToEnemyTransformed; m_flDistToEnemy = flDistToEnemyTransformed; } } // Give enemies that are farther away a longer grace period float fDistanceRatio = m_flDistToEnemy / PORTAL_FLOOR_TURRET_RANGE; m_flShotTime = gpGlobals->curtime + fDistanceRatio * fDistanceRatio * PORTAL_FLOOR_TURRET_MAX_SHOT_DELAY; m_flLastSight = 0; SetThink( &CNPC_FloorTurret::ActiveThink ); SetEyeState( TURRET_EYE_SEE_TARGET ); SpinUp(); if ( gpGlobals->curtime > m_flNextActivateSoundTime ) { EmitSound( "NPC_FloorTurret.Activate" ); m_flNextActivateSoundTime = gpGlobals->curtime + 3.0; } return; } //Are we out of time and need to retract? if ( gpGlobals->curtime > m_flLastSight ) { //Before we retrace, make sure that we are spun down. m_flLastSight = 0; SetThink( &CNPC_FloorTurret::Retire ); return; } //Display that we're scanning m_vecGoalAngles.x = GetAbsAngles().x + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 1.5f ) * 20.0f ); m_vecGoalAngles.y = GetAbsAngles().y + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 2.5f ) * 20.0f ); //Turn and ping UpdateFacing(); Ping(); // Update rope positions for ( int iRope = 0; iRope < PORTAL_FLOOR_TURRET_NUM_ROPES; ++iRope ) { if ( m_hRopes[ iRope ] ) { m_hRopes[ iRope ]->EndpointsChanged(); } } }
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; }
void CNPC_Portal_FloorTurret::ActiveThink( void ) { LaserOn(); //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_ACTIVE ) ) return; HackFindEnemy(); //Update our think time SetNextThink( gpGlobals->curtime + 0.1f ); CBaseEntity *pEnemy = GetEnemy(); //If we've become inactive, go back to searching if ( ( m_bActive == false ) || ( pEnemy == NULL ) ) { SetEnemy( NULL ); m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT; SetThink( &CNPC_FloorTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); return; } //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = pEnemy->BodyTarget( vecMid ); // Store off our last seen location so we can suppress it later m_vecEnemyLKP = vecMidEnemy; //Look for our current enemy bool bEnemyInFOV = FInViewCone( pEnemy ); bool bEnemyVisible = FVisible( pEnemy ) && pEnemy->IsAlive(); //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); // If the enemy isn't in the normal fov, check the fov through portals CProp_Portal *pPortal = NULL; if ( pEnemy->IsAlive() ) { pPortal = FInViewConeThroughPortal( pEnemy ); if ( pPortal && FVisibleThroughPortal( pPortal, pEnemy ) ) { // Translate our target across the portal Vector vecMidEnemyTransformed; UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vecMidEnemy, vecMidEnemyTransformed ); //Calculate dir and dist to enemy Vector vecDirToEnemyTransformed = vecMidEnemyTransformed - vecMid; float flDistToEnemyTransformed = VectorNormalize( vecDirToEnemyTransformed ); // If it's not visible through normal means or the enemy is closer through the portal, use the translated info if ( !bEnemyInFOV || !bEnemyVisible || flDistToEnemyTransformed < m_flDistToEnemy ) { bEnemyInFOV = true; bEnemyVisible = true; vecMidEnemy = vecMidEnemyTransformed; vecDirToEnemy = vecDirToEnemyTransformed; m_flDistToEnemy = flDistToEnemyTransformed; } else { pPortal = NULL; } } else { pPortal = NULL; } } //Draw debug info if ( g_debug_turret.GetBool() ) { NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( GetEnemy()->WorldSpaceCenter(), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMid, GetEnemy()->WorldSpaceCenter(), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMidEnemy, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMid, vecMidEnemy, 0, 255, 0, false, 0.05f ); } //See if they're past our FOV of attack if ( bEnemyInFOV == false ) { // Should we look for a new target? ClearEnemyMemory(); SetEnemy( NULL ); if ( m_spawnflags & SF_FLOOR_TURRET_FASTRETIRE ) { // Retire quickly in this case. (The case where we saw the player, but he hid again). m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_SHORT_WAIT; } else { m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT; } SetThink( &CNPC_FloorTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); SpinDown(); return; } //Current enemy is not visible if ( ( bEnemyVisible == false ) || ( m_flDistToEnemy > PORTAL_FLOOR_TURRET_RANGE )) { m_flLastSight = gpGlobals->curtime + 2.0f; ClearEnemyMemory(); SetEnemy( NULL ); SetThink( &CNPC_FloorTurret::SuppressThink ); return; } if ( g_debug_turret.GetBool() ) { Vector vecMuzzle, vecMuzzleDir; UpdateMuzzleMatrix(); MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir ); MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle ); // Visualize vertical firing ranges for ( int i = 0; i < 4; i++ ) { QAngle angMaxDownPitch = GetAbsAngles(); switch( i ) { case 0: angMaxDownPitch.x -= 15; break; case 1: angMaxDownPitch.x += 15; break; case 2: angMaxDownPitch.x -= 25; break; case 3: angMaxDownPitch.x += 25; break; default: break; } Vector vecMaxDownPitch; AngleVectors( angMaxDownPitch, &vecMaxDownPitch ); NDebugOverlay::Line( vecMuzzle, vecMuzzle + (vecMaxDownPitch*256), 255, 255, 255, false, 0.1 ); } } if ( m_flShotTime < gpGlobals->curtime ) { Vector vecMuzzle, vecMuzzleDir; UpdateMuzzleMatrix(); MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir ); MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle ); Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D(); Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D(); bool bCanShoot = true; float minCos3d = DOT_10DEGREE; // 10 degrees slop if ( m_flDistToEnemy < 60.0 ) { vecDirToEnemy2D.NormalizeInPlace(); vecMuzzleDir2D.NormalizeInPlace(); bCanShoot = ( vecDirToEnemy2D.Dot(vecMuzzleDir2D) >= DOT_10DEGREE ); minCos3d = 0.7071; // 45 degrees } //Fire the gun if ( bCanShoot ) // 10 degree slop XY { float dot3d = DotProduct( vecDirToEnemy, vecMuzzleDir ); if( m_bOutOfAmmo ) { DryFire(); } else { if ( dot3d >= minCos3d ) { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); SetActivity( (Activity)( ( m_bShootWithBottomBarrels ) ? ( ACT_FLOOR_TURRET_FIRE2 ) : ( ACT_FLOOR_TURRET_FIRE ) ) ); //Fire the weapon #if !DISABLE_SHOT Shoot( vecMuzzle, vecMuzzleDir, (dot3d < DOT_10DEGREE) ); #endif } } } } else { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); } //If we can see our enemy, face it if ( bEnemyVisible ) { //We want to look at the enemy's eyes so we don't jitter Vector vEnemyWorldSpaceCenter = pEnemy->WorldSpaceCenter(); if ( pPortal && pPortal->IsActivedAndLinked() ) { // Translate our target across the portal UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vEnemyWorldSpaceCenter, vEnemyWorldSpaceCenter ); } Vector vecDirToEnemyEyes = vEnemyWorldSpaceCenter - vecMid; VectorNormalize( vecDirToEnemyEyes ); QAngle vecAnglesToEnemy; VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy ); m_vecGoalAngles.y = vecAnglesToEnemy.y; m_vecGoalAngles.x = vecAnglesToEnemy.x; } //Turn to face UpdateFacing(); }