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; }
//----------------------------------------------------------------------------- // Purpose: for the MoveInterval, interpolate desired speed, calc actual distance traveled //----------------------------------------------------------------------------- float CAI_BlendedMotor::GetMoveScriptDist( float &flNewSpeed ) { int i; float flTotalDist = 0; float t = GetMoveInterval(); //CE_assert //Assert( m_scriptMove.Count() > 1); flNewSpeed = 0; for (i = 0; i < m_scriptMove.Count()-1; i++) { if (t < m_scriptMove[i].flTime) { // get new velocity float a = t / m_scriptMove[i].flTime; flNewSpeed = m_scriptMove[i].flMaxVelocity * (1 - a) + m_scriptMove[i+1].flMaxVelocity * a; // get distance traveled over this entry flTotalDist += (m_scriptMove[i].flMaxVelocity + flNewSpeed) * 0.5 * t; break; } else { // used all of entries time, get entries total movement flNewSpeed = m_scriptMove[i+1].flMaxVelocity; flTotalDist += m_scriptMove[i].flDist; t -= m_scriptMove[i].flTime; } } return flTotalDist; }
float CAI_BlendedMotor::GetMoveScriptYaw( void ) { int i; // interpolate desired angle float flNewYaw = GetAbsAngles().y; float t = GetMoveInterval(); for (i = 0; i < m_scriptTurn.Count()-1; i++) { if (t < m_scriptTurn[i].flTime) { // get new direction float a = t / m_scriptTurn[i].flTime; float deltaYaw = UTIL_AngleDiff( m_scriptTurn[i+1].flYaw, m_scriptTurn[i].flYaw ); flNewYaw = UTIL_AngleMod( m_scriptTurn[i].flYaw + a * deltaYaw ); break; } else { t -= m_scriptTurn[i].flTime; } } return flNewYaw; }
//----------------------------------------------------------------------------- // Purpose: Look ahead my stopping distance, or at least my hull width //----------------------------------------------------------------------------- float CAI_Motor::MinCheckDist( void ) { // Take the groundspeed into account float flMoveDist = GetMoveInterval() * GetIdealSpeed(); float flMinDist = max( MinStoppingDist(), flMoveDist); if ( flMinDist < GetHullWidth() ) flMinDist = GetHullWidth(); return flMinDist; }
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; }
void CAI_Motor::MoveFacing( const AILocalMoveGoal_t &move ) { if ( GetOuter()->OverrideMoveFacing( move, GetMoveInterval() ) ) return; // required movement direction float flMoveYaw = UTIL_VecToYaw( move.dir ); int nSequence = GetSequence(); float fSequenceMoveYaw = GetSequenceMoveYaw( nSequence ); if ( fSequenceMoveYaw == NOMOTION ) { fSequenceMoveYaw = 0; } if (!HasPoseParameter( nSequence, "move_yaw" )) { SetIdealYawAndUpdate( UTIL_AngleMod( flMoveYaw - fSequenceMoveYaw ) ); } else { // FIXME: move this up to navigator so that path goals can ignore these overrides. Vector dir; float flInfluence = GetFacingDirection( dir ); dir = move.facing * (1 - flInfluence) + dir * flInfluence; VectorNormalize( dir ); // ideal facing direction float idealYaw = UTIL_AngleMod( UTIL_VecToYaw( dir ) ); // FIXME: facing has important max velocity issues SetIdealYawAndUpdate( idealYaw ); // find movement direction to compensate for not being turned far enough float flDiff = UTIL_AngleDiff( flMoveYaw, GetLocalAngles().y ); SetPoseParameter( "move_yaw", flDiff ); /* if ((GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)) { Msg( "move %.1f : diff %.1f : ideal %.1f\n", flMoveYaw, flDiff, m_IdealYaw ); } */ } }
//----------------------------------------------------------------------------- float CAI_Motor::CalcIntervalMove() { // assuming linear acceleration, how far will I travel? return 0.5 * (GetCurSpeed() + GetIdealSpeed()) * GetMoveInterval(); }
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; }