//----------------------------------------------------------------------------- // Purpose: // Input : flInterval - // - // *pTraceResult - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CAI_BaseNPC::AutoMovement( float flInterval, CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult ) { bool ignored; Vector newPos; QAngle newAngles; if (flInterval <= 0.0) return true; m_ScheduleState.bTaskRanAutomovement = true; if (GetIntervalMovement( flInterval, ignored, newPos, newAngles )) { // DevMsg( "%.2f : (%.1f) %.1f %.1f %.1f\n", gpGlobals->curtime, (newPos - GetLocalOrigin()).Length(), newPos.x, newPos.y, newAngles.y ); if ( m_hCine ) { m_hCine->ModifyScriptedAutoMovement( &newPos ); } if (GetMoveType() == MOVETYPE_STEP) { if (!(GetFlags() & FL_FLY)) { if ( !pTarget ) { pTarget = GetNavTargetEntity(); } // allow NPCs to adjust the automatic movement if ( ModifyAutoMovement( newPos ) ) { // Set our motor's speed here Vector vecOriginalPosition = GetAbsOrigin(); bool bResult = false; if (!TaskIsComplete()) { bResult = ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS ); } Vector change = GetAbsOrigin() - vecOriginalPosition; if (flInterval != 0) { change /= flInterval; } GetMotor()->SetMoveVel(change); return bResult; } return ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS ); } else { // FIXME: here's no direct interface to a fly motor, plus this needs to support a state where going through the world is okay. // FIXME: add callbacks into the script system for validation // FIXME: add function on scripts to force only legal movements // FIXME: GetIntervalMovement deals in Local space, nor global. Currently now way to communicate that through these interfaces. SetLocalOrigin( newPos ); SetLocalAngles( newAngles ); return true; } } else if (GetMoveType() == MOVETYPE_FLY) { Vector dist = newPos - GetLocalOrigin(); VectorScale( dist, 1.0 / flInterval, dist ); SetLocalVelocity( dist ); return true; } } return false; }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CASW_Alien_Jumper::ShouldJump( void ) { if ( GetEnemy() == NULL ) return false; // don't jump if we're stunned if (m_bElectroStunned) return false; //Too soon to try to jump if ( m_flJumpTime > gpGlobals->curtime ) return false; // only jump if you're on the ground if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP ) return false; // Don't jump if I'm not allowed if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false ) return false; Vector vEnemyForward, vForward; GetEnemy()->GetVectors( &vEnemyForward, NULL, NULL ); GetVectors( &vForward, NULL, NULL ); float flDot = DotProduct( vForward, vEnemyForward ); if ( flDot < 0.5f ) flDot = 0.5f; Vector vecPredictedPos; //Get our likely position in two seconds UTIL_PredictedPosition( GetEnemy(), flDot * 2.5f, &vecPredictedPos ); // Don't jump if we're already near the target if ( ( GetAbsOrigin() - vecPredictedPos ).LengthSqr() < (512*512) ) return false; //Don't retest if the target hasn't moved enough //FIXME: Check your own distance from last attempt as well if ( ( ( m_vecLastJumpAttempt - vecPredictedPos ).LengthSqr() ) < (128*128) ) { m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } Vector targetDir = ( vecPredictedPos - GetAbsOrigin() ); float flDist = VectorNormalize( targetDir ); // don't jump at target it it's very close if (flDist < ANTLION_JUMP_MIN) return false; Vector targetPos = vecPredictedPos + ( targetDir * (GetHullWidth()*4.0f) ); // Try the jump AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), targetPos, MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), targetPos, 255, 0, 0, 0, 5 ); } m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 ); } //Save this jump in case the next time fails m_vecSavedJump = moveTrace.vJumpVelocity; m_vecLastJumpAttempt = targetPos; return true; }
//----------------------------------------------------------------------------- // Purpose: Handles all flight movement. // Input : flInterval - Seconds to simulate. //----------------------------------------------------------------------------- void CNPC_Crow::MoveCrowFly( float flInterval ) { // // Bound interval so we don't get ludicrous motion when debugging // or when framerate drops catastrophically. // if (flInterval > 1.0) { flInterval = 1.0; } m_flDangerSoundTime = gpGlobals->curtime + 5.0f; // // Determine the goal of our movement. // Vector vecMoveGoal = GetAbsOrigin(); if ( GetNavigator()->IsGoalActive() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); if ( GetNavigator()->CurWaypointIsGoal() == false ) { AI_ProgressFlyPathParams_t params( MASK_NPCSOLID ); params.bTrySimplify = false; GetNavigator()->ProgressFlyPath( params ); // ignore result, crow handles completion directly // Fly towards the hint. if ( GetNavigator()->GetPath()->GetCurWaypoint() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); } } } else { // No movement goal. vecMoveGoal = GetAbsOrigin(); SetAbsVelocity( vec3_origin ); return; } Vector vecMoveDir = ( vecMoveGoal - GetAbsOrigin() ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); // // Fly towards the movement goal. // float flDistance = ( vecMoveGoal - GetAbsOrigin() ).Length(); if ( vecMoveGoal != m_vDesiredTarget ) { m_vDesiredTarget = vecMoveGoal; } else { m_vCurrentTarget = ( m_vDesiredTarget - GetAbsOrigin() ); VectorNormalize( m_vCurrentTarget ); } float flLerpMod = 0.25f; if ( flDistance <= 256.0f ) { flLerpMod = 1.0f - ( flDistance / 256.0f ); } VectorLerp( vForward, m_vCurrentTarget, flLerpMod, vForward ); if ( flDistance < CROW_AIRSPEED * flInterval ) { if ( GetNavigator()->IsGoalActive() ) { if ( GetNavigator()->CurWaypointIsGoal() ) { m_bReachedMoveGoal = true; } else { GetNavigator()->AdvancePath(); } } else m_bReachedMoveGoal = true; } if ( GetHintNode() ) { AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, GetAbsOrigin(), GetNavigator()->GetCurWaypointPos(), MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { Vector vNodePos = vecMoveGoal; GetHintNode()->GetPosition(this, &vNodePos); GetNavigator()->SetGoal( vNodePos ); } } // // Look to see if we are going to hit anything. // VectorNormalize( vForward ); Vector vecDeflect; if ( Probe( vForward, CROW_AIRSPEED * flInterval, vecDeflect ) ) { vForward = vecDeflect; VectorNormalize( vForward ); } SetAbsVelocity( vForward * CROW_AIRSPEED ); if ( GetAbsVelocity().Length() > 0 && GetNavigator()->CurWaypointIsGoal() && flDistance < CROW_AIRSPEED ) { SetIdealActivity( (Activity)ACT_CROW_LAND ); } //Bank and set angles. Vector vRight; QAngle vRollAngle; VectorAngles( vForward, vRollAngle ); vRollAngle.z = 0; AngleVectors( vRollAngle, NULL, &vRight, NULL ); float flRoll = DotProduct( vRight, vecMoveDir ) * 45; flRoll = clamp( flRoll, -45, 45 ); vRollAngle[ROLL] = flRoll; SetAbsAngles( vRollAngle ); }