AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, float yaw) { const float climbSpeed = 100.0; Vector moveDir = climbDest - GetLocalOrigin(); float flDist = VectorNormalize( moveDir ); SetSmoothedVelocity( moveDir * climbSpeed ); if ( flDist < climbSpeed * GetMoveInterval() ) { if (flDist <= 1e-2) flDist = 0; const float climbTime = flDist / climbSpeed; SetMoveInterval( GetMoveInterval() - climbTime ); SetLocalOrigin( climbDest ); return AIMR_CHANGE_TYPE; } else { SetMoveInterval( 0 ); } // -------------------------------------------- // Turn to face the climb // -------------------------------------------- SetIdealYawAndUpdate( yaw ); return AIMR_OK; }
AIMotorMoveResult_t CAI_Motor::MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ) { // -------------------------------------------- // turn in the direction of movement // -------------------------------------------- MoveFacing( move ); // -------------------------------------------- float flNewSpeed = GetIdealSpeed(); // -------------------------------------------- // calculate actual travel distance // -------------------------------------------- // assuming linear acceleration, how far will I travel? float flTotal = 0.5 * (GetCurSpeed() + flNewSpeed) * GetMoveInterval(); // can I move farther in this interval than I'm supposed to? if ( flTotal > move.maxDist ) { if ( !(move.flags & AILMG_CONSUME_INTERVAL) ) { // only use a portion of the time interval SetMoveInterval( GetMoveInterval() * (1 - move.maxDist / flTotal) ); } else SetMoveInterval( 0 ); flTotal = move.maxDist; } else { // use all the time SetMoveInterval( 0 ); } SetMoveVel( move.dir * flNewSpeed ); // -------------------------------------------- // walk the distance // -------------------------------------------- AIMotorMoveResult_t result = AIM_SUCCESS; if ( flTotal > 0.0 ) { Vector vecFrom = GetLocalOrigin(); Vector vecTo = vecFrom + move.dir * flTotal; result = MoveGroundStep( vecTo, move.pMoveTarget, -1, true, pTraceResult ); if ( result == AIM_FAILED ) MoveStop(); } else if ( !OnMoveStalled( move ) ) { result = AIM_FAILED; } return result; }
AIMotorMoveResult_t CAI_Motor::MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ) { // turn in the direction of movement MoveFacing( move ); // calc accel/decel rates float flNewSpeed = GetIdealSpeed(); SetMoveVel( move.dir * flNewSpeed ); float flTotal = 0.5 * (GetCurSpeed() + flNewSpeed) * GetMoveInterval(); float distance = move.maxDist; // can I move farther in this interval than I'm supposed to? if (flTotal > distance) { // only use a portion of the time interval SetMoveInterval( GetMoveInterval() * (1 - distance / flTotal) ); flTotal = distance; } else { // use all the time SetMoveInterval( 0 ); } Vector vecStart, vecEnd; vecStart = GetLocalOrigin(); VectorMA( vecStart, flTotal, move.dir, vecEnd ); AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, vecStart, vecEnd, MASK_NPCSOLID, NULL, &moveTrace ); if ( pTraceResult ) *pTraceResult = moveTrace; // Check for total blockage if (fabs(moveTrace.flDistObstructed - flTotal) <= 1e-1) { // But if we bumped into our target, then we succeeded! if ( move.pMoveTarget && (moveTrace.pObstruction == move.pMoveTarget) ) return AIM_PARTIAL_HIT_TARGET; return AIM_FAILED; } // The true argument here causes it to touch all triggers // in the volume swept from the previous position to the current position UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true); return (IsMoveBlocked(moveTrace.fStatus)) ? AIM_PARTIAL_HIT_WORLD : AIM_SUCCESS; }
AIMotorMoveResult_t CAI_Motor::MoveGroundExecuteWalk( const AILocalMoveGoal_t &move, float speed, float dist, AIMoveTrace_t *pTraceResult ) { bool bReachingLocalGoal = ( dist > move.maxDist ); // can I move farther in this interval than I'm supposed to? if ( bReachingLocalGoal ) { if ( !(move.flags & AILMG_CONSUME_INTERVAL) ) { // only use a portion of the time interval SetMoveInterval( GetMoveInterval() * (1 - move.maxDist / dist) ); } else SetMoveInterval( 0 ); dist = move.maxDist; } else { // use all the time SetMoveInterval( 0 ); } SetMoveVel( move.dir * speed ); // -------------------------------------------- // walk the distance // -------------------------------------------- AIMotorMoveResult_t result = AIM_SUCCESS; if ( dist > 0.0 ) { Vector vecFrom = GetLocalOrigin(); Vector vecTo = vecFrom + move.dir * dist; if ( move.navType == NAV_CRAWL ) { char *pchHackBoolToInt = (char*)(&bReachingLocalGoal); *pchHackBoolToInt = 2; } result = MoveGroundStep( vecTo, move.pMoveTarget, -1, true, bReachingLocalGoal, pTraceResult ); if ( result == AIM_FAILED ) MoveStop(); } else if ( !OnMoveStalled( move ) ) { result = AIM_FAILED; } return result; }
AIMoveResult_t CAI_Motor::MoveJumpStop() { SetSmoothedVelocity( Vector(0,0,0) ); if (GetOuter()->GetActivity() == ACT_GLIDE) { float flTime = GetOuter()->GetGroundChangeTime(); GetOuter()->AddStepDiscontinuity( flTime, GetAbsOrigin(), GetAbsAngles() ); if ( SelectWeightedSequence( ACT_LAND ) == ACT_INVALID ) return AIMR_CHANGE_TYPE; SetActivity( ACT_LAND ); // FIXME: find out why the client doesn't interpolate immediatly after sequence change // GetOuter()->SetCycle( flTime - gpGlobals->curtime ); } if (GetOuter()->GetActivity() != ACT_LAND || GetOuter()->IsActivityFinished()) { return AIMR_CHANGE_TYPE; } SetMoveInterval( 0 ); SetGravity( 1.0f ); return AIMR_OK; }
int CAI_Motor::MoveJumpExecute( ) { // needs to detect being hit SetIdealYawAndUpdate( GetSmoothedVelocity() ); SetActivity( ACT_GLIDE ); // use all the time SetMoveInterval( 0 ); return AIMR_OK; }
int CAI_Motor::MoveJumpExecute( ) { // needs to detect being hit UpdateYaw( ); if (GetOuter()->GetActivity() == ACT_JUMP && GetOuter()->IsActivityFinished()) { SetActivity( ACT_GLIDE ); } // use all the time SetMoveInterval( 0 ); return AIMR_OK; }
AIMoveResult_t CAI_Motor::MoveNormalExecute( const AILocalMoveGoal_t &move ) { AI_PROFILE_SCOPE(CAI_Motor_MoveNormalExecute); // -------------------------------- AIMotorMoveResult_t fMotorResult; AIMoveTrace_t moveTrace; if ( move.navType == NAV_GROUND ) { fMotorResult = MoveGroundExecute( move, &moveTrace ); } else { Assert( move.navType == NAV_FLY ); fMotorResult = MoveFlyExecute( move, &moveTrace ); } static AIMoveResult_t moveResults[] = { AIMR_ILLEGAL, // AIM_FAILED AIMR_OK, // AIM_SUCCESS AIMR_BLOCKED_NPC, // AIM_PARTIAL_HIT_NPC AIMR_BLOCKED_WORLD, // AIM_PARTIAL_HIT_WORLD AIMR_BLOCKED_WORLD, // AIM_PARTIAL_HIT_TARGET }; Assert( ARRAYSIZE( moveResults ) == AIM_NUM_RESULTS && fMotorResult >= 0 && fMotorResult <= ARRAYSIZE( moveResults ) ); AIMoveResult_t result = moveResults[fMotorResult]; if ( result != AIMR_OK ) { OnMoveExecuteFailed( move, moveTrace, fMotorResult, &result ); SetMoveInterval( 0 ); // always consume interval on failure, even if overridden by OnMoveExecuteFailed() } return DbgResult( result ); }
AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw, int climbNodesLeft ) { if ( fabsf( climbDir.z ) > .1 ) { if ( GetActivity() != ACT_CLIMB_DISMOUNT ) { Activity desiredActivity = (climbDir.z > -0.01 ) ? ACT_CLIMB_UP : ACT_CLIMB_DOWN; if ( GetActivity() != desiredActivity ) { SetActivity( desiredActivity ); } } if ( GetActivity() != ACT_CLIMB_UP && GetActivity() != ACT_CLIMB_DOWN && GetActivity() != ACT_CLIMB_DISMOUNT ) { DevMsg( "Climber not in a climb activity!\n" ); return AIMR_ILLEGAL; } if (m_nDismountSequence != ACT_INVALID) { if (GetActivity() == ACT_CLIMB_UP ) { if (climbNodesLeft <= 2 && climbDist < fabs( m_vecDismount.z )) { // fixme: No other way to force m_nIdealSequence? GetOuter()->SetActivity( ACT_CLIMB_DISMOUNT ); GetOuter()->SetCycle( GetOuter()->GetMovementFrame( m_vecDismount.z - climbDist ) ); } } } } float climbSpeed = GetOuter()->GetInstantaneousVelocity(); if (m_nDismountSequence != ACT_INVALID) { // catch situations where the climb mount/dismount finished before reaching goal climbSpeed = MAX( climbSpeed, 30.0 ); } else { // FIXME: assume if they don't have a dismount animation then they probably don't really support climbing. climbSpeed = 100.0; } SetSmoothedVelocity( climbDir * climbSpeed ); if ( climbDist < climbSpeed * GetMoveInterval() ) { if (climbDist <= 1e-2) climbDist = 0; const float climbTime = climbDist / climbSpeed; SetMoveInterval( GetMoveInterval() - climbTime ); SetLocalOrigin( climbDest ); return AIMR_CHANGE_TYPE; } else { SetMoveInterval( 0 ); } // -------------------------------------------- // Turn to face the climb // -------------------------------------------- SetIdealYawAndUpdate( yaw ); return AIMR_OK; }
AIMotorMoveResult_t CAI_BlendedMotor::MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ) { if ( move.curExpectedDist < 0.001 ) return BaseClass::MoveFlyExecute( move, pTraceResult ); BuildMoveScript( move, pTraceResult ); float flNewSpeed = GetCurSpeed(); float flTotalDist = GetMoveScriptDist( flNewSpeed ); Assert( move.maxDist < 0.01 || flTotalDist > 0.0 ); // -------------------------------------------- // turn in the direction of movement // -------------------------------------------- float flNewYaw = GetMoveScriptYaw( ); // get facing based on movement yaw AILocalMoveGoal_t move2 = move; move2.facing = UTIL_YawToVector( flNewYaw ); // turn in the direction needed MoveFacing( move2 ); GetOuter()->m_flGroundSpeed = GetSequenceGroundSpeed( GetSequence()); SetMoveScriptAnim( flNewSpeed ); // DevMsg( "%6.2f : Speed %.1f : %.1f\n", gpGlobals->curtime, flNewSpeed, GetIdealSpeed() ); // reset actual "sequence" ground speed based current movement sequence, orientation // FIXME: the above is redundant with MoveGroundExecute, and the below is a mix of MoveGroundExecuteWalk and MoveFlyExecute bool bReachingLocalGoal = ( flTotalDist > move.maxDist ); // can I move farther in this interval than I'm supposed to? if ( bReachingLocalGoal ) { if ( !(move.flags & AILMG_CONSUME_INTERVAL) ) { // only use a portion of the time interval SetMoveInterval( GetMoveInterval() * (1 - move.maxDist / flTotalDist) ); } else SetMoveInterval( 0 ); flTotalDist = move.maxDist; } else { // use all the time SetMoveInterval( 0 ); } SetMoveVel( move.dir * flNewSpeed ); // orig Vector vecStart, vecEnd; vecStart = GetLocalOrigin(); VectorMA( vecStart, flTotalDist, move.dir, vecEnd ); AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, vecStart, vecEnd, MASK_NPCSOLID, NULL, &moveTrace ); if ( pTraceResult ) *pTraceResult = moveTrace; // Check for total blockage if (fabs(moveTrace.flDistObstructed - flTotalDist) <= 1e-1) { // But if we bumped into our target, then we succeeded! if ( move.pMoveTarget && (moveTrace.pObstruction == move.pMoveTarget) ) return AIM_PARTIAL_HIT_TARGET; return AIM_FAILED; } // The true argument here causes it to touch all triggers // in the volume swept from the previous position to the current position UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true); return (IsMoveBlocked(moveTrace.fStatus)) ? AIM_PARTIAL_HIT_WORLD : AIM_SUCCESS; }