void CAI_BlendedMotor::MoveJumpStart( const Vector &velocity ) { // TODO: merge transitions with movement script if (m_iPrimaryLayer != -1) { SetLayerWeight( m_iPrimaryLayer, 0 ); } if (m_iSecondaryLayer != -1) { SetLayerWeight( m_iSecondaryLayer, 0 ); } BaseClass::MoveJumpStart( velocity ); }
void CAI_BlendedMotor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw ) { // TODO: merge transitions with movement script if (m_iPrimaryLayer != -1) { SetLayerWeight( m_iPrimaryLayer, 0 ); } if (m_iSecondaryLayer != -1) { SetLayerWeight( m_iSecondaryLayer, 0 ); } BaseClass::MoveClimbStart( climbDest, climbDir, climbDist, yaw ); }
//----------------------------------------------------------------------------- // Purpose: // Input : *actor - // *parameters - //----------------------------------------------------------------------------- void CBaseFlex::AddFlexSequence( CExpressionInfo *info ) { if ( !info ) return; CChoreoEvent *event = info->m_pEvent; if ( !event ) return; CChoreoScene *scene = info->m_pScene; if ( !scene ) return; if (info->m_iLayer >= 0) { SetLayerWeight( info->m_iLayer, event->GetIntensity( scene->GetTime() ) ); } }
void CAI_BlendedMotor::MoveContinue() { m_nPrimarySequence = GetInteriorSequence( ACT_INVALID ); m_nGoalSequence = m_nPrimarySequence; Assert( m_nPrimarySequence != ACT_INVALID ); if (m_nPrimarySequence == ACT_INVALID) return; m_flStartCycle = 0.0; m_iPrimaryLayer = AddLayeredSequence( m_nPrimarySequence, 0 ); SetLayerWeight( m_iPrimaryLayer, 0.0 ); SetLayerPlaybackRate( m_iPrimaryLayer, 0.0 ); SetLayerNoRestore( m_iPrimaryLayer, true ); SetLayerCycle( m_iPrimaryLayer, m_flStartCycle, m_flStartCycle ); m_bDeceleratingToGoal = false; }
//----------------------------------------------------------------------------- // Purpose: // Input : *actor - // *parameters - //----------------------------------------------------------------------------- void CBaseFlex::AddFlexGesture( CExpressionInfo *info ) { if ( !info ) return; CChoreoEvent *event = info->m_pEvent; if ( !event ) return; CChoreoScene *scene = info->m_pScene; if ( !scene ) return; if (info->m_iLayer >= 0) { // this happens after StudioFrameAdvance() float duration = event->GetDuration( ); float orig_duration = SequenceDuration( info->m_nSequence ); // when we come by again after StudioFrameAdvance() has moved forward 0.1 seconds, what frame should we be on? float flCycle = GetLayerCycle( info->m_iLayer ); float flNextCycle = event->GetShiftedTimeFromReferenceTime( (m_flAnimTime - info->m_flStartAnim + 0.1) / duration ); // FIXME: what time should this use? SetLayerWeight( info->m_iLayer, event->GetIntensity( scene->GetTime() ) ); float rate = (flNextCycle - flCycle) * orig_duration / 0.1; /* Msg( "%d : %.2f (%.2f) : %.3f %.3f : %.3f\n", info->m_iLayer, scene->GetTime(), (scene->GetTime() - event->GetStartTime()) / duration, flCycle, flNextCycle, rate ); */ SetLayerPlaybackRate( info->m_iLayer, rate ); } }
void CAI_BlendedMotor::MoveStart() { if (m_nPrimarySequence == -1) { m_nPrimarySequence = GetSequence(); m_flStartCycle = GetCycle(); m_flCurrRate = 0.4; // Assert( !GetOuter()->HasMovement( m_nStartSequence ) ); m_nSecondarySequence = -1; m_iPrimaryLayer = AddLayeredSequence( m_nPrimarySequence, 0 ); SetLayerWeight( m_iPrimaryLayer, 0.0 ); SetLayerPlaybackRate( m_iPrimaryLayer, 0.0 ); SetLayerNoRestore( m_iPrimaryLayer, true ); SetLayerCycle( m_iPrimaryLayer, m_flStartCycle, m_flStartCycle ); m_flSecondaryWeight = 0.0; } else { // suspect that MoveStop() wasn't called when the previous route finished // Assert( 0 ); } if (m_nGoalSequence == ACT_INVALID) { ResetGoalSequence(); } m_vecPrevOrigin2 = GetAbsOrigin(); m_vecPrevOrigin1 = GetAbsOrigin(); m_bDeceleratingToGoal = false; }
void CAI_BlendedMotor::SetMoveScriptAnim( float flNewSpeed ) { // don't bother if the npc is dead if (!GetOuter()->IsAlive()) return; // insert ideal layers // FIXME: needs full transitions, as well as starting vs stopping sequences, leaning, etc. CAI_Navigator *pNavigator = GetNavigator(); SetPlaybackRate( m_flCurrRate ); // calc weight of idle animation layer that suppresses the run animation float flWeight = 0.0; if (GetIdealSpeed() > 0.0) { flWeight = 1.0 - (flNewSpeed / (GetIdealSpeed() * GetPlaybackRate())); } if (flWeight < 0.0) { m_flCurrRate = flNewSpeed / GetIdealSpeed(); m_flCurrRate = clamp( m_flCurrRate, 0.0, 1.0 ); SetPlaybackRate( m_flCurrRate ); flWeight = 0.0; } // Msg("weight %.3f rate %.3f\n", flWeight, m_flCurrRate ); m_flCurrRate = min( m_flCurrRate + (1.0 - m_flCurrRate) * 0.8, 1.0 ); if (m_nSavedGoalActivity == ACT_INVALID) { ResetGoalSequence(); } // detect state change Activity activity = GetOuter()->NPC_TranslateActivity( m_nSavedGoalActivity ); if ( activity != m_nSavedTranslatedGoalActivity ) { m_nSavedTranslatedGoalActivity = activity; m_nInteriorSequence = ACT_INVALID; m_nGoalSequence = pNavigator->GetArrivalSequence( m_nPrimarySequence ); } if (m_bDeceleratingToGoal) { // find that sequence to play when at goal m_nGoalSequence = pNavigator->GetArrivalSequence( m_nPrimarySequence ); if (m_nGoalSequence == ACT_INVALID) { m_nGoalSequence = GetInteriorSequence( m_nPrimarySequence ); } Assert( m_nGoalSequence != ACT_INVALID ); } if (m_flSecondaryWeight == 1.0 || (m_iSecondaryLayer != -1 && m_nPrimarySequence == m_nSecondarySequence)) { // secondary layer at full strength last time, delete the primary and shift down RemoveLayer( m_iPrimaryLayer, 0.0, 0.0 ); m_iPrimaryLayer = m_iSecondaryLayer; m_nPrimarySequence = m_nSecondarySequence; m_iSecondaryLayer = -1; m_nSecondarySequence = ACT_INVALID; m_flSecondaryWeight = 0.0; } // look for transition sequence if needed if (m_nSecondarySequence == ACT_INVALID) { if (!m_bDeceleratingToGoal && m_nGoalSequence != GetInteriorSequence( m_nPrimarySequence )) { // strob interior sequence in case it changed m_nGoalSequence = GetInteriorSequence( m_nPrimarySequence ); } if (m_nGoalSequence != ACT_INVALID && m_nPrimarySequence != m_nGoalSequence) { // Msg("From %s to %s\n", GetOuter()->GetSequenceName( m_nPrimarySequence ), GetOuter()->GetSequenceName( m_nGoalSequence ) ); m_nSecondarySequence = GetOuter()->FindTransitionSequence(m_nPrimarySequence, m_nGoalSequence, NULL); if (m_nSecondarySequence == ACT_INVALID) m_nSecondarySequence = m_nGoalSequence; } } // set blending for if (m_nSecondarySequence != ACT_INVALID) { if (m_iSecondaryLayer == -1) { m_iSecondaryLayer = AddLayeredSequence( m_nSecondarySequence, 0 ); SetLayerWeight( m_iSecondaryLayer, 0.0 ); if (m_nSecondarySequence == m_nGoalSequence) { SetLayerPlaybackRate( m_iSecondaryLayer, 0.0 ); } else { SetLayerPlaybackRate( m_iSecondaryLayer, 1.0 ); } SetLayerNoRestore( m_iSecondaryLayer, true ); m_flSecondaryWeight = 0.0; } m_flSecondaryWeight = min( m_flSecondaryWeight + 0.3, 1.0 ); if (m_flSecondaryWeight < 1.0) { SetLayerWeight( m_iPrimaryLayer, (flWeight - m_flSecondaryWeight * flWeight) / (1.0f - m_flSecondaryWeight * flWeight) ); SetLayerWeight( m_iSecondaryLayer, flWeight * m_flSecondaryWeight ); } else { SetLayerWeight( m_iPrimaryLayer, 0.0f ); SetLayerWeight( m_iSecondaryLayer, flWeight ); } } else { // recreate layer if missing if (m_iPrimaryLayer == -1) { MoveContinue(); } // try to catch a stale layer if (m_iSecondaryLayer != -1) { // secondary layer at full strength last time, delete the primary and shift down RemoveLayer( m_iSecondaryLayer, 0.0, 0.0 ); m_iSecondaryLayer = -1; m_nSecondarySequence = ACT_INVALID; m_flSecondaryWeight = 0.0; } // debounce // flWeight = flWeight * 0.5 + 0.5 * GetOuter()->GetLayerWeight( m_iPrimaryLayer ); SetLayerWeight( m_iPrimaryLayer, flWeight ); } }
bool CAI_BlendedMotor::AddTurnGesture( float flYD ) { // some funky bug with human turn gestures, disable for now return false; // try using a turn gesture Activity activity = ACT_INVALID; float weight = 1.0; float turnCompletion = 1.0; if (m_flNextTurnGesture > gpGlobals->curtime) { /* if ( GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) { Msg( "%.1f : [ %.2f ]\n", flYD, m_flNextTurnAct - gpGlobals->curtime ); } */ return false; } if ( GetOuter()->IsMoving() || GetOuter()->IsCrouching() ) { return false; } if (fabs( flYD ) < 15) { return false; } else if (flYD < -45) { activity = ACT_GESTURE_TURN_RIGHT90; weight = flYD / -90; turnCompletion = 0.36; } else if (flYD < 0) { activity = ACT_GESTURE_TURN_RIGHT45; weight = flYD / -45; turnCompletion = 0.4; } else if (flYD <= 45) { activity = ACT_GESTURE_TURN_LEFT45; weight = flYD / 45; turnCompletion = 0.4; } else { activity = ACT_GESTURE_TURN_LEFT90; weight = flYD / 90; turnCompletion = 0.36; } int seq = SelectWeightedSequence( activity ); if (scene_flatturn->GetBool() && GetOuter()->IsCurSchedule( SCHED_SCENE_GENERIC )) { Activity flatactivity = activity; if (activity == ACT_GESTURE_TURN_RIGHT90) { flatactivity = ACT_GESTURE_TURN_RIGHT90_FLAT; } else if (activity == ACT_GESTURE_TURN_RIGHT45) { flatactivity = ACT_GESTURE_TURN_RIGHT45_FLAT; } else if (activity == ACT_GESTURE_TURN_LEFT90) { flatactivity = ACT_GESTURE_TURN_LEFT90_FLAT; } else if (activity == ACT_GESTURE_TURN_LEFT45) { flatactivity = ACT_GESTURE_TURN_LEFT45_FLAT; } if (flatactivity != activity) { int newseq = SelectWeightedSequence( flatactivity ); if (newseq != ACTIVITY_NOT_AVAILABLE) { seq = newseq; } } } if (seq != ACTIVITY_NOT_AVAILABLE) { int iLayer = GetOuter()->AddGestureSequence( seq ); if (iLayer != -1) { GetOuter()->SetLayerPriority( iLayer, 100 ); // vary the playback a bit SetLayerPlaybackRate( iLayer, 1.0 ); float actualDuration = GetOuter()->GetLayerDuration( iLayer ); float rate = enginerandom->RandomFloat( 0.5, 1.1 ); float diff = fabs( flYD ); float speed = (diff / (turnCompletion * actualDuration / rate)) * 0.1; speed = clamp( speed, 15, 35 ); speed = min( speed, diff ); actualDuration = (diff / (turnCompletion * speed)) * 0.1 ; GetOuter()->SetLayerDuration( iLayer, actualDuration ); SetLayerWeight( iLayer, weight ); SetYawSpeed( speed ); Remember( bits_MEMORY_TURNING ); // don't overlap the turn portion of the gestures, and don't play them too often m_flNextTurnGesture = gpGlobals->curtime + max( turnCompletion * actualDuration, 0.3 ); /* if ( GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) { Msg( "%.1f : %.2f %.2f : %.2f (%.2f)\n", flYD, weight, speed, actualDuration, turnCompletion * actualDuration ); } */ return true; } else { return false; } } return false; }
//----------------------------------------------------------------------------- // Purpose: Add string indexed scene/expression/duration to list of active expressions // Input : scenefile - // expression - // duration - //----------------------------------------------------------------------------- void CBaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event ) { if ( !scene || !event ) { Msg( "CBaseFlex::AddExpression: scene or event was NULL!!!\n" ); return; } CExpressionInfo info; info.m_pEvent = event; info.m_pScene = scene; info.m_bStarted = false; switch ( event->GetType() ) { case CChoreoEvent::SEQUENCE: { info.m_nSequence = LookupSequence( event->GetParameters() ); info.m_iLayer = -1; if (info.m_nSequence >= 0) { info.m_iLayer = AddLayeredSequence( info.m_nSequence, scene->GetChannelIndex( event->GetChannel()) ); SetLayerWeight( info.m_iLayer, 0.0 ); info.m_flStartAnim = m_flAnimTime; // ?? } } break; case CChoreoEvent::GESTURE: { info.m_nSequence = LookupSequence( event->GetParameters() ); info.m_iLayer = -1; if (info.m_nSequence >= 0) { // this happens before StudioFrameAdvance() info.m_iLayer = AddLayeredSequence( info.m_nSequence, scene->GetChannelIndex( event->GetChannel()) ); SetLayerDuration( info.m_iLayer, event->GetDuration() ); SetLayerWeight( info.m_iLayer, 0.0 ); bool looping = ((GetSequenceFlags( info.m_nSequence ) & STUDIO_LOOPING) != 0); if ( looping ) { DevMsg( 1, "vcd error, gesture %s of model %s is marked as STUDIO_LOOPING!\n", event->GetParameters(), GetModelName() ); } SetLayerLooping( info.m_iLayer, false ); // force to not loop // figure out the animtime when this was frame 0 float dt = scene->GetTime() - event->GetStartTime(); info.m_flStartAnim = m_flAnimTime - dt; // ?? float flCycle = 0; // assuming anim time is going to advance 0.1 seconds, what should our new cycle be? float duration = event->GetDuration( ); float orig_duration = SequenceDuration( info.m_nSequence ); SetLayerCycle( info.m_iLayer, 0.0 ); float flNextCycle = event->GetShiftedTimeFromReferenceTime( (m_flAnimTime - info.m_flStartAnim + 0.1) / duration ); float rate = (flNextCycle - flCycle) * orig_duration / 0.1; SetLayerPlaybackRate( info.m_iLayer, rate ); } } break; } m_Expressions.AddToTail( info ); }