//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. OVERRIDDEN for bullsquid because it needs to // know explicitly when the last attempt to chase the enemy // failed, since that impacts its attack choices. //========================================================= void CNPC_Bullsquid::StartTask ( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_MELEE_ATTACK2: { if (GetEnemy()) { GrowlSound(); m_flLastAttackTime = gpGlobals->curtime; BaseClass::StartTask ( pTask ); } break; } case TASK_SQUID_HOPTURN: { SetActivity ( ACT_HOP ); if ( GetEnemy() ) { Vector vecFacing = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ); VectorNormalize( vecFacing ); GetMotor()->SetIdealYaw( vecFacing ); } break; } case TASK_SQUID_EAT: { m_flHungryTime = gpGlobals->curtime + pTask->flTaskData; TaskComplete(); break; } default: { BaseClass::StartTask ( pTask ); break; } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_PassengerBehaviorZombie::StartDismount( void ) { // Leap off the vehicle int nSequence = FindExitSequence(); Assert( nSequence != -1 ); SetTransitionSequence( nSequence ); GetOuter()->SetIdealActivity( ACT_SCRIPT_CUSTOM_MOVE ); // This removes the NPC from the vehicle's handling and fires all necessary outputs m_hVehicle->RemovePhysicsChild( GetOuter() ); m_hVehicle->NPC_RemovePassenger( GetOuter() ); m_hVehicle->NPC_FinishedExitVehicle( GetOuter(), (IsPassengerHostile()==false) ); // Detach from the parent GetOuter()->SetParent( NULL ); GetOuter()->SetMoveType( MOVETYPE_STEP ); GetMotor()->SetYawLocked( false ); QAngle vecAngles = GetAbsAngles(); vecAngles.z = 0.0f; GetOuter()->SetAbsAngles( vecAngles ); // HACK: Will this work? IPhysicsObject *pPhysObj = GetOuter()->VPhysicsGetObject(); if ( pPhysObj != NULL ) { pPhysObj->EnableCollisions( true ); } // Clear this m_PassengerIntent = PASSENGER_INTENT_NONE; SetPassengerState( PASSENGER_STATE_EXITING ); // Get the velocity Vector vecUp, vecJumpDir; GetOuter()->GetVectors( &vecJumpDir, NULL, &vecUp ); // Move back and up vecJumpDir *= random->RandomFloat( -400.0f, -500.0f ); vecJumpDir += vecUp * 150.0f; GetOuter()->SetAbsVelocity( vecJumpDir ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_PolicingBehavior::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_POLICE_FACE_ALONG_GOAL: { GetMotor()->UpdateYaw(); if ( GetOuter()->FacingIdeal() ) { TaskComplete(); } break; } default: BaseClass::RunTask( pTask); } }
void CASW_Parasite::DoJumpFromEgg() { SetContextThink( NULL, gpGlobals->curtime, s_pParasiteAnimThink ); SetParent( NULL ); SetAbsOrigin( GetAbsOrigin() + Vector( 0, 0, 30 ) ); // TODO: position parasite at where his 'idle in egg' animation has him. This has to be some distance off the ground, else the jump will immediately end. Vector dir = vec3_origin; AngleVectors( GetAbsAngles(), &dir ); //Vector vecJumpPos = GetAbsOrigin()+ Vector(19,0,60)+ dir * m_flEggJumpDistance; Vector vecJumpPos = GetAbsOrigin() + dir * m_flEggJumpDistance; SetActivity( ACT_RANGE_ATTACK1 ); StudioFrameAdvanceManual( 0.0 ); SetParent( NULL ); RemoveFlag( FL_FLY ); AddEffects( EF_NOINTERP ); m_bDoEggIdle = false; GetMotor()->SetIdealYaw( GetAbsAngles().y ); JumpAttack( false, vecJumpPos, false ); }
//========================================================= // RunTask //========================================================= void CNPC_Houndeye::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HOUND_THREAT_DISPLAY: { GetMotor()->SetIdealYawToTargetAndUpdate( GetEnemyLKP(), AI_KEEP_YAW_SPEED ); if ( IsActivityFinished() ) { TaskComplete(); } break; } case TASK_HOUND_CLOSE_EYE: { /*//<<TEMP>> if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) { pev->skin++; } */ break; } case TASK_HOUND_HOP_BACK: { if ( IsActivityFinished() ) { TaskComplete(); } break; } default: { BaseClass::RunTask(pTask); break; } } }
//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. OVERRIDDEN for bullsquid because it needs to // know explicitly when the last attempt to chase the enemy // failed, since that impacts its attack choices. //========================================================= void CNPC_Bullsquid::StartTask ( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_MELEE_ATTACK2: { CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "Bullsquid.Growl" ); BaseClass::StartTask ( pTask ); break; } case TASK_SQUID_HOPTURN: { SetActivity ( ACT_HOP ); if ( GetEnemy() ) { Vector vecFacing = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ); VectorNormalize( vecFacing ); GetMotor()->SetIdealYaw( vecFacing ); } break; } case TASK_SQUID_EAT: { m_flHungryTime = gpGlobals->curtime + pTask->flTaskData; break; } default: { BaseClass::StartTask ( pTask ); break; } } }
AI_SuggestorResult_t CAI_PlaneSolver::GenerateObstacleSuggestion( const AILocalMoveGoal_t &goal, float yawScanCenter, float probeDist, float spanPerProbe, int probeOffset) { AIMoveTrace_t moveTrace; float yawTest; float arcCenter; CalcYawsFromOffset( yawScanCenter, spanPerProbe, probeOffset, &yawTest, &arcCenter ); Vector probeDir = UTIL_YawToVector( yawTest ); float requiredMovement = goal.speed * GetMotor()->GetMoveInterval(); // Probe immediate move with footing, then look further out ignoring footing bool fTraceClear = true; if ( probeDist > requiredMovement ) { if ( !MoveLimit( goal.navType, GetLocalOrigin() + probeDir * requiredMovement, !ProbeForNpcs(), true, &moveTrace ) ) { fTraceClear = false; moveTrace.flDistObstructed = (probeDist - requiredMovement) + moveTrace.flDistObstructed; } } if ( fTraceClear ) { fTraceClear = MoveLimit( goal.navType, GetLocalOrigin() + probeDir * probeDist, !ProbeForNpcs(), false, &moveTrace ); } if ( !fTraceClear ) { GenerateSuggestionFromTrace( goal, moveTrace, probeDist, arcCenter, spanPerProbe, probeOffset ); return SR_OK; } return SR_NONE; }
//------------------------------------------------------------------------------ // Purpose: routine called every frame when a task is running // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_MeleeBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_MELEE_FLIP_AROUND: { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetLocalOrigin(), AI_KEEP_YAW_SPEED ); } if ( GetOuter()->IsActivityFinished() ) { TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CNPC_Cremator::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CREMATOR_IDLE: { SetActivity( ACT_IDLE ); if( IsActivityFinished() ) { TaskComplete(); } break; } case TASK_CREMATOR_RANGE_ATTACK1: { Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); break; } default: BaseClass::StartTask( pTask ); break; } }
//========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= void CNPC_HL1Barney::SetYawSpeed ( void ) { int ys; ys = 0; switch ( GetActivity() ) { case ACT_IDLE: ys = 70; break; case ACT_WALK: ys = 70; break; case ACT_RUN: ys = 90; break; default: ys = 70; break; } GetMotor()->SetYawSpeed( ys ); }
//----------------------------------------------------------------------------- // 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 : int //----------------------------------------------------------------------------- int CNPC_Bug_Warrior::SelectSchedule( void ) { ClearCondition( COND_WBUG_STOP_FLEEING ); // Turn towards sounds if ( HasCondition(COND_HEAR_DANGER) || HasCondition(COND_HEAR_COMBAT) ) { CSound *pSound = GetBestSound(); if ( pSound) { if ( !HasCondition( COND_SEE_ENEMY ) && ( pSound->m_iType & (SOUND_PLAYER | SOUND_COMBAT) ) ) { GetMotor()->SetIdealYawToTarget( pSound->GetSoundReactOrigin() ); } } } switch ( m_NPCState ) { case NPC_STATE_IDLE: { // If I have an enemy, but I don't have any nearby friends, flee if ( HasCondition( COND_SEE_ENEMY ) && ShouldFlee() ) { SetState( NPC_STATE_ALERT ); return SCHED_WBUG_FLEE_ENEMY; } // Fellow bug might be requesting assistance if ( HasCondition( COND_WBUG_ASSIST_FELLOW_BUG ) ) return SCHED_WBUG_ASSIST_FELLOW_BUG; // BugHole might be requesting help if ( HasCondition( COND_WBUG_RETURN_TO_BUGHOLE ) ) return SCHED_WBUG_RETURN_TO_BUGHOLE; // Return to my bughole return SCHED_WBUG_RETURN_TO_BUGHOLE_AND_REMOVE; break; } case NPC_STATE_ALERT: { // If I have an enemy, but I don't have any nearby friends, flee if ( HasCondition( COND_SEE_ENEMY ) && ShouldFlee() ) { SetState( NPC_STATE_ALERT ); return SCHED_WBUG_FLEE_ENEMY; } // Fellow bug might be requesting assistance if ( HasCondition( COND_WBUG_ASSIST_FELLOW_BUG ) ) return SCHED_WBUG_ASSIST_FELLOW_BUG; // BugHole might be requesting help if ( HasCondition( COND_WBUG_RETURN_TO_BUGHOLE ) ) return SCHED_WBUG_RETURN_TO_BUGHOLE; // If I have a patrol path, walk it if ( m_iszPatrolPathName != NULL_STRING ) return SCHED_WBUG_PATROL; break; } case NPC_STATE_COMBAT: { // Did I lose my enemy? if ( HasCondition ( COND_LOST_ENEMY ) || HasCondition ( COND_ENEMY_UNREACHABLE ) ) { SetEnemy( NULL ); m_bFightingToDeath = false; SetState(NPC_STATE_IDLE); return BaseClass::SelectSchedule(); } // If I have an enemy, but I don't have any nearby friends, flee if ( HasCondition( COND_SEE_ENEMY ) && ShouldFlee() ) return SCHED_WBUG_FLEE_ENEMY; // If we're able to melee, do so if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) return BaseClass::SelectSchedule(); } break; } return BaseClass::SelectSchedule(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_FuncTankBehavior::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_FACE_FUNCTANK: { Assert( m_hFuncTank ); GetMotor()->UpdateYaw(); if ( GetOuter()->FacingIdeal() ) { TaskComplete(); } break; } case TASK_HOLSTER_WEAPON: { Assert( m_hFuncTank ); if ( GetOuter()->IsWeaponHolstered() ) { GetOuter()->SpeakSentence( FUNCTANK_SENTENCE_JUST_MOUNTED ); // We are at the correct position and facing for the func_tank, mount it. m_hFuncTank->StartControl( GetOuter() ); GetOuter()->ClearEnemyMemory(); m_bMounted = true; TaskComplete(); GetOuter()->SetIdealActivity( ACT_IDLE_MANNEDGUN ); } break; } case TASK_FIRE_FUNCTANK: { Assert( m_hFuncTank ); if( GetOuter()->m_flWaitFinished < gpGlobals->curtime ) { TaskComplete(); } if ( m_hFuncTank->NPC_HasEnemy() ) { GetOuter()->SetLastAttackTime( gpGlobals->curtime ); m_hFuncTank->NPC_Fire(); // The NPC may have decided to stop using the func_tank, because it's out of ammo. if ( !m_hFuncTank ) { TaskComplete(); break; } } else { TaskComplete(); } Assert( m_hFuncTank ); if ( m_hFuncTank->GetAmmoCount() == 0 ) { TaskComplete(); } break; } case TASK_SCAN_LEFT_FUNCTANK: case TASK_SCAN_RIGHT_FUNCTANK: { GetMotor()->UpdateYaw(); if ( GetOuter()->FacingIdeal() ) { TaskComplete(); } break; } case TASK_FORGET_ABOUT_FUNCTANK: { m_hFuncTank->NPC_InterruptRoute(); SetBusy( gpGlobals->curtime + AI_FUNCTANK_BEHAVIOR_BUSYTIME ); TaskComplete(); break; } default: { BaseClass::RunTask( pTask ); break; } } }
void CAI_LeadBehavior::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_LEAD_FACE_GOAL: { if ( m_goalyaw != -1 ) { GetMotor()->SetIdealYaw( m_goalyaw ); } TaskComplete(); break; } case TASK_LEAD_SUCCEED: { Speak( TLK_LEAD_SUCCESS ); NotifyEvent( LBE_SUCCESS ); break; } case TASK_LEAD_ARRIVE: { // Only speak the first time we arrive if ( !m_hasspokenarrival ) { Speak( TLK_LEAD_ARRIVAL ); NotifyEvent( LBE_ARRIVAL ); m_hasspokenarrival = true; } else { TaskComplete(); } break; } case TASK_STOP_LEADING: { ClearGoal(); TaskComplete(); break; } case TASK_GET_PATH_TO_LEAD_GOAL: { if ( GetNavigator()->SetGoal( m_goal ) ) { TaskComplete(); } else { TaskFail("NO PATH"); } break; } case TASK_LEAD_GET_PATH_TO_WAITPOINT: { if ( GetNavigator()->SetGoal( m_waitpoint ) ) { TaskComplete(); } else { TaskFail("NO PATH"); } break; } case TASK_LEAD_WALK_PATH: { // If we're leading, and we're supposed to run, run instead of walking if ( m_run && ( IsCurSchedule( SCHED_LEAD_WAITFORPLAYER, false ) || IsCurSchedule( SCHED_LEAD_PLAYER, false ) || IsCurSchedule( SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER, false )|| IsCurSchedule( SCHED_LEAD_RETRIEVE, false ) ) ) { ChainStartTask( TASK_RUN_PATH ); } else { ChainStartTask( TASK_WALK_PATH ); } break; } case TASK_LEAD_WAVE_TO_PLAYER: { // Wave to the player if we can see him. Otherwise, just idle. if ( HasCondition( COND_SEE_PLAYER ) ) { Speak( TLK_LEAD_ATTRACTPLAYER ); if ( HaveSequenceForActivity(ACT_SIGNAL1) ) { SetActivity(ACT_SIGNAL1); } } else { SetActivity(ACT_IDLE); } TaskComplete(); break; } case TASK_LEAD_PLAYER_NEEDS_WEAPON: { float flAvailableTime = GetOuter()->GetExpresser()->GetSemaphoreAvailableTime( GetOuter() ); // if someone else is talking, don't speak if ( flAvailableTime <= gpGlobals->curtime ) { Speak( TLK_LEAD_MISSINGWEAPON ); } SetActivity(ACT_IDLE); TaskComplete(); break; } case TASK_LEAD_SPEAK_START: { m_hasspokenstart = true; Speak( TLK_LEAD_START ); SetActivity(ACT_IDLE); TaskComplete(); break; } case TASK_LEAD_MOVE_TO_RANGE: { // If we haven't spoken our start speech, move closer if ( !m_hasspokenstart) { ChainStartTask( TASK_MOVE_TO_GOAL_RANGE, m_leaddistance - 24 ); } else { ChainStartTask( TASK_MOVE_TO_GOAL_RANGE, m_retrievedistance ); } break; } case TASK_LEAD_RETRIEVE_WAIT: { m_MoveMonitor.SetMark( AI_GetSinglePlayer(), 24 ); ChainStartTask( TASK_WAIT_INDEFINITE ); break; } case TASK_STOP_MOVING: { BaseClass::StartTask( pTask); if ( IsCurSchedule( SCHED_LEAD_PAUSE, false ) && pTask->flTaskData == 1 ) { GetNavigator()->SetArrivalDirection( GetTarget() ); } break; } case TASK_WAIT_FOR_SPEAK_FINISH: { BaseClass::StartTask( pTask); if( GetOuter()->GetState() == NPC_STATE_COMBAT ) { // Don't stand around jabbering in combat. TaskComplete(); } // If we're not supposed to wait for the player, don't wait for speech to finish. // Instead, just wait a wee tad, and then start moving. NPC will speak on the go. if ( TaskIsRunning() && !m_args.iRetrievePlayer ) { if ( gpGlobals->curtime - GetOuter()->GetTimeTaskStarted() > 0.3 ) { TaskComplete(); } } break; } default: BaseClass::StartTask( pTask); } }
//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_Dog::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_DOG_PICKUP_ITEM: { PullObject( false ); } break; case TASK_DOG_GET_PATH_TO_PHYSOBJ: { //Check this cause our object might have been deleted. if ( m_hPhysicsEnt == NULL ) FindPhysicsObject( NULL ); //And if we still can't find anything, then just go away. if ( m_hPhysicsEnt == NULL ) { TaskFail( "Can't find an object I like!" ); return; } IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) m_hPhysicsEnt->SetOwnerEntity( this ); if ( pPhysicsObject ) pPhysicsObject->RecheckCollisionFilter(); vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); bool bBuiltRoute = false; //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; bBuiltRoute = GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); if ( bBuiltRoute == true ) TaskComplete(); else { m_flTimeToCatch = gpGlobals->curtime + 0.1; m_flNextRouteTime = gpGlobals->curtime + 0.3; m_flNextSwat = gpGlobals->curtime + 0.1; if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 ) m_hUnreachableObjects.AddToTail( m_hPhysicsEnt ); m_hPhysicsEnt = NULL; GetNavigator()->ClearGoal(); } } break; case TASK_WAIT: { if ( IsWaitFinished() ) { TaskComplete(); } if ( m_hPhysicsEnt ) { if ( m_bHasObject == false ) { GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); GetMotor()->UpdateYaw(); } } break; } case TASK_DOG_LAUNCH_ITEM: if( IsActivityFinished() ) { if ( m_hPhysicsEnt ) { m_hPhysicsEnt->SetOwnerEntity( NULL ); } TaskComplete(); } break; case TASK_DOG_WAIT_FOR_TARGET_TO_FACE: { if ( CanTargetSeeMe() ) TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: { if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() ) { BaseClass::RunTask( pTask ); return; } if ( m_hPhysicsEnt != NULL ) { IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( !pPhysObj ) { Warning( "npc_dog TASK_WAIT_FOR_MOVEMENT with NULL m_hPhysicsEnt->VPhysicsGetObject\n" ); } if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) TaskFail( "Player picked it up!" ); //If the object is moving then my old goal might not be valid //cancel the schedule and make it restart again in a bit. if ( pPhysObj && pPhysObj->IsAsleep() == false && GetNavigator()->IsGoalActive() == false ) { Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); GetNavigator()->ClearGoal(); float flDistance = (vecGoalPos - GetLocalOrigin()).Length(); //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); if ( flDistance <= DOG_PHYSOBJ_MOVE_TO_DIST ) { TaskComplete(); GetNavigator()->StopMoving(); } } } BaseClass::RunTask( pTask ); } break; case TASK_DOG_WAIT_FOR_OBJECT: { if ( m_hPhysicsEnt != NULL ) { if ( FVisible( m_hPhysicsEnt ) == false ) { m_flTimeToCatch = 0.0f; ClearBeams(); TaskFail( "Lost sight of the object!" ); m_hPhysicsEnt->SetOwnerEntity( NULL ); return; } m_hPhysicsEnt->SetOwnerEntity( this ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); Vector vGunPos; GetAttachment( m_iPhysGunAttachment, vGunPos ); Vector vToObject = m_hPhysicsEnt->WorldSpaceCenter() - vGunPos; float flDistance = vToObject.Length(); VectorNormalize( vToObject ); SetAim( m_hPhysicsEnt->WorldSpaceCenter() - GetAbsOrigin() ); #ifdef SecobMod__Enable_Fixed_Multiplayer_AI CBasePlayer *pPlayer = UTIL_GetNearestVisiblePlayer(this); #else CBasePlayer *pPlayer = AI_GetSinglePlayer(); #endif //SecobMod__Enable_Fixed_Multiplayer_AI float flDistanceToPlayer = flDistance; if ( pPlayer ) { flDistanceToPlayer = (pPlayer->GetAbsOrigin() - m_hPhysicsEnt->WorldSpaceCenter()).Length(); } IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( !pPhysObj ) { Warning( "npc_dog: TASK_DOG_WAIT_FOR_OBJECT with m_hPhysicsEnt->VPhysicsGetObject == NULL\n" ); } if ( pPhysObj && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) && flDistanceToPlayer > ( flDistance * 2 ) ) { if ( m_flTimeToPull <= gpGlobals->curtime ) { Vector vCurrentVel; float flCurrentVel; AngularImpulse vCurrentAI; pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI ); flCurrentVel = vCurrentVel.Length(); VectorNormalize( vCurrentVel ); if ( pPhysObj && flDistance <= DOG_PULL_DISTANCE ) { Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ); VectorNormalize( vDir ); vCurrentVel = vCurrentVel * ( flCurrentVel * DOG_PULL_VELOCITY_MOD ); vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD; pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI ); vDir = vDir * flDistance * DOG_PULL_TO_GUN_VEL_MOD; Vector vAngle( 0, 0, 0 ); pPhysObj->AddVelocity( &vDir, &vAngle ); CreateBeams(); } float flDot = DotProduct( vCurrentVel, vForward ); if ( flDistance >= DOG_PULL_DISTANCE && flDistance <= ( DOG_PULL_DISTANCE * 2 ) && flDot > -0.3 ) { if ( pPhysObj->IsAsleep() == false && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) { Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); GetNavigator()->ClearGoal(); //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); } } } } float flDirDot = DotProduct( vToObject, vForward ); if ( flDirDot < 0.2 ) { GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); GetMotor()->UpdateYaw(); } if ( m_flTimeToCatch < gpGlobals->curtime && m_bDoWaitforObjectBehavior == false ) { m_hPhysicsEnt->SetOwnerEntity( NULL ); m_flTimeToCatch = 0.0f; ClearBeams(); TaskFail( "Done waiting!" ); } else if ( pPhysObj && ( flDistance <= DOG_CATCH_DISTANCE && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) ) { AngularImpulse vZero( 0, 0, 0 ); pPhysObj->SetVelocity( &vec3_origin, &vZero ); GetNavigator()->StopMoving(); //Fire Output! m_OnCatch.FireOutput( this, this ); m_bHasObject = true; ClearBeams(); TaskComplete(); } } else { GetNavigator()->StopMoving(); ClearBeams(); TaskFail("No Physics Object!"); } } break; case TASK_DOG_CATCH_OBJECT: if( IsActivityFinished() ) { m_flTimeToCatch = 0.0f; TaskComplete(); } break; default: BaseClass::RunTask( pTask ); break; } }
// Основная атака огнеметом // This is the cremator's main attack, or more precisely, its damage function. void CNPC_Cremator::DispatchSpray( CBaseEntity *pEntity ) { Vector vecSrc, vecAim; trace_t tr; //const char *entityname = pEntity->GetClassname(); Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); vecSrc = GetAbsOrigin() + up * 36; vecAim = GetShootEnemyDir( vecSrc ); float deflection = 0.01; vecAim = vecAim + 1 * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); /* if ( tr.DidHitWorld() ) // spawn flames on solid surfaces. // It's not very important since it is extremely rare for a cremator to // hit brush geometry but might be a nice feature for a close-space combat // it also works fine but again is EXTREMELY hard to get in-game { Vector ofsDir = ( tr.endpos - GetAbsOrigin() ); float offset = VectorNormalize( ofsDir ); if ( offset > 128 ) offset = 128; float scale = 0.1f + ( 0.75f * ( 1.0f - ( offset / 128.0f ) ) ); float growth = 0.1f + ( 0.75f * (offset / 128.0f ) ); if ( tr.surface.flags & CONTENTS_GRATE ) // get smaller flames on grates since they have a smaller burning area { scale = 0.1f + ( 0.15f * ( 1.0f - ( offset / 128.0f ) ) ); } else { scale = 0.1f + ( 0.75f * ( 1.0f - ( offset / 128.0f ) ) ); } FireSystem_StartFire( tr.endpos, scale, growth, 8.0, 10.0f, (SF_FIRE_START_ON|SF_FIRE_START_FULL), (CBaseEntity*) this, FIRE_NATURAL ); } */ pEntity = tr.m_pEnt; if ( pEntity != NULL && m_takedamage ) { CTakeDamageInfo firedamage( this, this, sk_cremator_firedamage.GetFloat(), DMG_BURN ); CTakeDamageInfo radiusdamage( this, this, sk_cremator_radiusdamage.GetFloat(), DMG_PLASMA ); CalculateMeleeDamageForce( &firedamage, vecAim, tr.endpos ); RadiusDamage ( CTakeDamageInfo ( this, this, 2, DMG_PLASMA ), // AOE; this stuff makes cremators absurdly powerfull sometimes btw tr.endpos, 64.0f, CLASS_NONE, NULL ); pEntity->DispatchTraceAttack( ( firedamage ), vecAim, &tr ); Vector flEnemyLKP = pEntity->GetAbsOrigin(); GetMotor()->SetIdealYawToTargetAndUpdate( flEnemyLKP ); ClearMultiDamage(); } m_iAmmo --; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_AssaultBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: BaseClass::StartTask( pTask ); break; case TASK_ASSAULT_DEFER_SCHEDULE_SELECTION: m_flTimeDeferScheduleSelection = gpGlobals->curtime + pTask->flTaskData; TaskComplete(); break; case TASK_ASSAULT_MOVE_AWAY_PATH: break; case TASK_ANNOUNCE_CLEAR: { // If we're at an assault point that can never be cleared, keep waiting forever (if it's the last point in the assault) if ( m_hAssaultPoint && !m_hAssaultPoint->HasSpawnFlags( SF_ASSAULTPOINT_CLEARONARRIVAL ) && m_hAssaultPoint->m_bNeverTimeout && m_hAssaultPoint->m_NextAssaultPointName == NULL_STRING ) { TaskComplete(); return; } ClearAssaultPoint(); TaskComplete(); } break; case TASK_WAIT_ASSAULT_DELAY: { if( m_hRallyPoint ) { GetOuter()->SetWait( m_hRallyPoint->m_flAssaultDelay ); } else { TaskComplete(); } } break; case TASK_AWAIT_ASSAULT_TIMEOUT: // Maintain vigil for as long as the level designer has asked. Wait // and look for targets. GetOuter()->SetWait( m_hAssaultPoint->m_flAssaultTimeout ); break; case TASK_GET_PATH_TO_RALLY_POINT: { AI_NavGoal_t goal( m_hRallyPoint->GetAbsOrigin() ); goal.pTarget = m_hRallyPoint; if ( GetNavigator()->SetGoal( goal ) == false ) { // Try and get as close as possible otherwise AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hRallyPoint->GetAbsOrigin(), AIN_DEF_ACTIVITY, 256 ); if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) ) { //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it! ClearCondition( COND_TASK_FAILED ); GetNavigator()->SetArrivalDirection( m_hRallyPoint->GetAbsAngles() ); TaskComplete(); return; } } GetNavigator()->SetArrivalDirection( m_hRallyPoint->GetAbsAngles() ); } break; case TASK_FACE_RALLY_POINT: { UpdateForceCrouch(); GetMotor()->SetIdealYaw( m_hRallyPoint->GetAbsAngles().y ); GetOuter()->SetTurnActivity(); } break; case TASK_GET_PATH_TO_ASSAULT_POINT: { AI_NavGoal_t goal( m_hAssaultPoint->GetAbsOrigin() ); goal.pTarget = m_hAssaultPoint; if ( GetNavigator()->SetGoal( goal ) == false ) { // Try and get as close as possible otherwise AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hAssaultPoint->GetAbsOrigin(), AIN_DEF_ACTIVITY, 256 ); if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) ) { //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it! ClearCondition( COND_TASK_FAILED ); GetNavigator()->SetArrivalDirection( m_hAssaultPoint->GetAbsAngles() ); TaskComplete(); return; } } GetNavigator()->SetArrivalDirection( m_hAssaultPoint->GetAbsAngles() ); } break; case TASK_FACE_ASSAULT_POINT: { UpdateForceCrouch(); if( HasCondition( COND_CAN_RANGE_ATTACK1 ) ) { // If I can already fight when I arrive, don't bother running any facing code. Let // The combat AI do that. Turning here will only make the NPC look dumb in a combat // situation because it will take time to turn before attacking. TaskComplete(); } else { GetMotor()->SetIdealYaw( m_hAssaultPoint->GetAbsAngles().y ); GetOuter()->SetTurnActivity(); } } break; case TASK_HIT_ASSAULT_POINT: OnHitAssaultPoint(); TaskComplete(); break; case TASK_HIT_RALLY_POINT: // Once we're stading on it and facing the correct direction, // we have arrived at rally point. GetOuter()->SpeakSentence( ASSAULT_SENTENCE_HIT_RALLY_POINT ); m_bHitRallyPoint = true; m_hRallyPoint->m_OnArrival.FireOutput( GetOuter(), m_hRallyPoint, 0 ); TaskComplete(); break; case TASK_AWAIT_CUE: if( PollAssaultCue() ) { TaskComplete(); } else { // Don't do anything if we've been told to crouch if ( IsForcingCrouch() ) break; else if( m_hRallyPoint->m_RallySequenceName != NULL_STRING ) { // The cue hasn't been given yet, so set to the rally sequence. int sequence = GetOuter()->LookupSequence( STRING( m_hRallyPoint->m_RallySequenceName ) ); if( sequence != -1 ) { GetOuter()->ResetSequence( sequence ); GetOuter()->SetIdealActivity( ACT_DO_NOT_DISTURB ); } } else { // Only chain this task if I'm not playing a custom animation if( GetOuter()->GetEnemy() ) { ChainStartTask( TASK_FACE_ENEMY, 0 ); } } } break; default: BaseClass::StartTask( pTask ); break; } }
//========================================================= // RunTask //========================================================= void CNPC_Controller::RunTask ( const Task_t *pTask ) { if (m_flShootEnd > gpGlobals->curtime) { Vector vecHand; QAngle vecAngle; GetAttachment( 2, vecHand, vecAngle ); while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->curtime) { Vector vecSrc = vecHand + GetAbsVelocity() * (m_flShootTime - gpGlobals->curtime); Vector vecDir; if (GetEnemy() != NULL) { if (HasCondition( COND_SEE_ENEMY )) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + GetEnemy()->GetAbsVelocity() * 0.5; } else { m_vecEstVelocity = m_vecEstVelocity * 0.8; } vecDir = Intersect( vecSrc, GetEnemy()->BodyTarget( GetAbsOrigin() ), m_vecEstVelocity, sk_controller_speedball.GetFloat() ); float delta = 0.03490; // +-2 degree vecDir = vecDir + Vector( random->RandomFloat( -delta, delta ), random->RandomFloat( -delta, delta ), random->RandomFloat( -delta, delta ) ) * sk_controller_speedball.GetFloat(); vecSrc = vecSrc + vecDir * (gpGlobals->curtime - m_flShootTime); CAI_BaseNPC *pBall = (CAI_BaseNPC*)Create( "controller_energy_ball", vecSrc, GetAbsAngles(), this ); pBall->SetAbsVelocity( vecDir ); // DevMsg( 2, "controller shooting energy ball\n" ); } m_flShootTime += 0.2; } if (m_flShootTime > m_flShootEnd) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; m_iBall[1] = 64; m_iBallTime[1] = m_flShootEnd; m_fInCombat = FALSE; } } switch ( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: case TASK_WAIT_PVS: { if( GetEnemy() ) { float idealYaw = UTIL_VecToYaw( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ); GetMotor()->SetIdealYawAndUpdate( idealYaw ); } if ( IsSequenceFinished() || GetActivity() == ACT_IDLE) { m_fInCombat = false; } BaseClass::RunTask ( pTask ); if (!m_fInCombat) { if( HasCondition( COND_CAN_RANGE_ATTACK1 )) { SetActivity( ACT_RANGE_ATTACK1 ); SetCycle( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else if( HasCondition( COND_CAN_RANGE_ATTACK2 ) ) { SetActivity( ACT_RANGE_ATTACK2 ); SetCycle( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else { int iFloatActivity = LookupFloat(); if( IsSequenceFinished() || iFloatActivity != GetActivity() ) { SetActivity( (Activity)iFloatActivity ); } } } } break; default: BaseClass::RunTask ( pTask ); break; } }
//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_Dog::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_DOG_SETUP_THROW_TARGET: { SetupThrowTarget(); TaskComplete(); } break; case TASK_DOG_GET_PATH_TO_PHYSOBJ: { FindPhysicsObject( STRING( m_sObjectName ) ); if ( m_hPhysicsEnt == NULL ) { FindPhysicsObject( NULL ); return; } IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) m_hPhysicsEnt->SetOwnerEntity( this ); if ( pPhysicsObject ) pPhysicsObject->RecheckCollisionFilter(); vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; if ( GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ) == false ) { if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 ) m_hUnreachableObjects.AddToTail( m_hPhysicsEnt ); FindPhysicsObject( NULL, m_hPhysicsEnt ); m_flTimeToCatch = gpGlobals->curtime + 0.1; m_flNextRouteTime = gpGlobals->curtime + 0.3; m_flNextSwat = gpGlobals->curtime + 0.1; GetNavigator()->ClearGoal(); } else { TaskComplete(); } } break; case TASK_DOG_FACE_OBJECT: { if( m_hPhysicsEnt == NULL ) { // Physics Object is gone! Probably was an explosive // or something else broke it. TaskFail("Physics ent NULL"); return; } Vector vecDir; vecDir = m_hPhysicsEnt->WorldSpaceCenter() - GetLocalOrigin(); VectorNormalize(vecDir); GetMotor()->SetIdealYaw( UTIL_VecToYaw( vecDir ) ); TaskComplete(); } break; case TASK_DOG_PICKUP_ITEM: { if( m_hPhysicsEnt == NULL ) { // Physics Object is gone! Probably was an explosive // or something else broke it. TaskFail("Physics ent NULL"); return; } else { SetIdealActivity( (Activity)ACT_DOG_PICKUP ); } } break; case TASK_DOG_LAUNCH_ITEM: { if( m_hPhysicsEnt == NULL ) { // Physics Object is gone! Probably was an explosive // or something else broke it. TaskFail("Physics ent NULL"); return; } else { if ( m_hPhysicsEnt == NULL || m_bHasObject == false ) { TaskFail( "Don't have the item!" ); return; } SetIdealActivity( (Activity)ACT_DOG_THROW ); } } break; case TASK_DOG_WAIT_FOR_TARGET_TO_FACE: { if ( CanTargetSeeMe() ) TaskComplete(); } break; case TASK_DOG_WAIT_FOR_OBJECT: { SetIdealActivity( (Activity)ACT_DOG_WAITING ); } break; case TASK_DOG_CATCH_OBJECT: { SetIdealActivity( (Activity)ACT_DOG_CATCH ); } break; case TASK_DOG_DELAY_SWAT: m_flNextSwat = gpGlobals->curtime + pTask->flTaskData; if ( m_hThrowTarget == NULL ) #ifdef SecobMod__Enable_Fixed_Multiplayer_AI m_hThrowTarget = UTIL_GetNearestVisiblePlayer(this); #else m_hThrowTarget = AI_GetSinglePlayer(); #endif //SecobMod__Enable_Fixed_Multiplayer_AI TaskComplete(); break; default: BaseClass::StartTask( pTask ); } }
void CNPC_BigMomma::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CHECK_NODE_PROXIMITY: { } break; case TASK_FIND_NODE: { CBaseEntity *pTarget = GetTarget(); if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) { if ( pTarget ) m_iszTarget = pTarget->m_target; } NodeStart( m_iszTarget ); TaskComplete(); //Msg( "BM: Found node %s\n", STRING( m_iszTarget ) ); } break; case TASK_NODE_DELAY: m_nodeTime = gpGlobals->curtime + pTask->flTaskData; TaskComplete(); //Msg( "BM: FAIL! Delay %.2f\n", pTask->flTaskData ); break; case TASK_PROCESS_NODE: //Msg( "BM: Reached node %s\n", STRING( m_iszTarget ) ); NodeReach(); TaskComplete(); break; case TASK_PLAY_NODE_PRESEQUENCE: case TASK_PLAY_NODE_SEQUENCE: { const char *pSequence = NULL; int iSequence; if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) pSequence = GetNodeSequence(); else pSequence = GetNodePresequence(); //Msg( "BM: Playing node sequence %s\n", pSequence ); if ( pSequence ) //ugh { iSequence = LookupSequence( pSequence ); if ( iSequence != -1 ) { SetIdealActivity( ACT_DO_NOT_DISTURB ); SetSequence( iSequence ); SetCycle( 0.0f ); ResetSequenceInfo(); //Msg( "BM: Sequence %s %f\n", GetNodeSequence(), gpGlobals->curtime ); return; } } TaskComplete(); } break; case TASK_NODE_YAW: GetMotor()->SetIdealYaw( GetNodeYaw() ); TaskComplete(); break; case TASK_WAIT_NODE: m_flWait = gpGlobals->curtime + GetNodeDelay(); /*if ( GetTarget() && GetTarget()->GetSpawnFlags() & SF_INFOBM_WAIT ) Msg( "BM: Wait at node %s forever\n", STRING( m_iszTarget) ); else Msg( "BM: Wait at node %s for %.2f\n", STRING( m_iszTarget ), GetNodeDelay() );*/ break; case TASK_MOVE_TO_NODE_RANGE: { CBaseEntity *pTarget = GetTarget(); if ( !pTarget ) TaskFail( FAIL_NO_TARGET ); else { if ( ( pTarget->GetAbsOrigin() - GetAbsOrigin() ).Length() < GetNodeRange() ) TaskComplete(); else { Activity act = ACT_WALK; if ( pTarget->GetSpawnFlags() & SF_INFOBM_RUN ) act = ACT_RUN; AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, act ); if ( !GetNavigator()->SetGoal( goal ) ) { TaskFail( NO_TASK_FAILURE ); } } } } //Msg( "BM: Moving to node %s\n", STRING( m_iszTarget ) ); break; case TASK_MELEE_ATTACK1: { // Play an attack sound here CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "BigMomma.Attack" ); BaseClass::StartTask( pTask ); } break; default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_AssaultBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_WAIT_ASSAULT_DELAY: case TASK_AWAIT_ASSAULT_TIMEOUT: if ( m_hAssaultPoint ) { if ( m_hAssaultPoint->m_bInputForcedClear || (m_hAssaultPoint->m_bClearOnContact && HasCondition( COND_SEE_ENEMY )) ) { // If we're on an assault that should clear on contact, clear when we see an enemy TaskComplete(); } } if( GetOuter()->IsWaitFinished() && ( pTask->iTask == TASK_WAIT_ASSAULT_DELAY || !m_hAssaultPoint->m_bNeverTimeout ) ) { TaskComplete(); } break; case TASK_FACE_RALLY_POINT: case TASK_FACE_ASSAULT_POINT: GetMotor()->UpdateYaw(); if( HasCondition( COND_CAN_RANGE_ATTACK1 ) ) { // Out early if the NPC can attack. TaskComplete(); } if ( GetOuter()->FacingIdeal() ) { TaskComplete(); } break; case TASK_AWAIT_CUE: // If we've lost our rally point, abort if ( !m_hRallyPoint ) { TaskFail("No rally point."); break; } if( PollAssaultCue() ) { TaskComplete(); } if ( IsForcingCrouch() ) break; if( GetOuter()->GetEnemy() && m_hRallyPoint->m_RallySequenceName == NULL_STRING ) { // I have an enemy and I'm NOT playing a custom animation. ChainRunTask( TASK_FACE_ENEMY, 0 ); } break; case TASK_WAIT_FOR_MOVEMENT: if ( ai_debug_assault.GetBool() ) { if ( IsCurSchedule( SCHED_MOVE_TO_ASSAULT_POINT ) ) { NDebugOverlay::Line( WorldSpaceCenter(), GetNavigator()->GetGoalPos(), 255,0,0, true,0.1); NDebugOverlay::Box( GetNavigator()->GetGoalPos(), -Vector(10,10,10), Vector(10,10,10), 255,0,0, 8, 0.1 ); } else if ( IsCurSchedule( SCHED_MOVE_TO_RALLY_POINT ) ) { NDebugOverlay::Line( WorldSpaceCenter(), GetNavigator()->GetGoalPos(), 0,255,0, true,0.1); NDebugOverlay::Box( GetNavigator()->GetGoalPos(), -Vector(10,10,10), Vector(10,10,10), 0,255,0, 8, 0.1 ); } } if ( m_hAssaultPoint && (m_hAssaultPoint->m_bInputForcedClear || (m_hAssaultPoint->m_bClearOnContact && HasCondition( COND_SEE_ENEMY ))) ) { DevMsg( "Assault Cleared due to Contact or Input!\n" ); ClearAssaultPoint(); TaskComplete(); return; } BaseClass::RunTask( pTask ); break; default: BaseClass::RunTask( pTask ); break; } }
//------------------------------------------------------------------------------ // Purpose: routine called every frame when a task is running // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_ShieldBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_SHIELD_RAISE: { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetLocalOrigin(), AI_KEEP_YAW_SPEED ); } if ( GetOuter()->IsActivityFinished() ) { TaskComplete(); SetBehaviorParam( m_StatusParm, 1 ); } } break; case TASK_SHIELD_LOWER: if ( GetOuter()->IsActivityFinished() ) { TaskComplete(); SetBehaviorParam( m_StatusParm, 0 ); m_bShieldLowering = false; } break; case TASK_SHIELD_MAINTAIN: { bool bNoReset = false; if ( m_TurningGesture != ACT_INVALID ) { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetLocalOrigin(), AI_KEEP_YAW_SPEED ); } if ( GetOuter()->IsPlayingGesture( m_TurningGesture ) == false ) { TaskComplete(); m_TurningGesture = ACT_INVALID; if ( pTarget ) { float flIdealYaw = UTIL_VecToYaw( pTarget->GetAbsOrigin() - GetLocalOrigin() ); float flYawDiff = UTIL_AngleMod( GetLocalAngles().y - flIdealYaw ); if ( flYawDiff > 25.0f && flYawDiff < 335.0f ) { bNoReset = true; } } } } else if ( GetOuter()->IsActivityFinished() ) { TaskComplete(); } if ( m_flStartFrozenTime != -1.0f && m_flEndFrozenTime < gpGlobals->curtime && bNoReset == false ) { m_flStartFrozenTime = -1.0f; m_flStartDownTime = gpGlobals->curtime + m_flSFrozenDownTime; SetBehaviorParam( m_FrozenParm, 0 ); } } break; case TASK_SHIELD_MAINTAIN_FLIP: { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetLocalOrigin(), AI_KEEP_YAW_SPEED ); } if ( GetOuter()->IsActivityFinished() ) { TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
// Здесь происходит назначение различных ф-ций во время анимации. Аним-ивенты назначаются в .qc. void CNPC_Cremator::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case CREMATOR_AE_FLLEFT: // левый шаг { LeftFootHit( pEvent->eventtime ); } break; case CREMATOR_AE_FLRIGHT: // правый шаг { RightFootHit( pEvent->eventtime ); } break; case CREMATOR_AE_IMMO_START: // начало анимации атаки { //CBaseEntity *pEntity; DispatchSpray( this ); DevMsg( "%i ammo left\n", m_iAmmo ); Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTargetAndUpdate( flEnemyLKP ); } break; case CREMATOR_AE_IMMO_PARTICLE: // Маркер для запуска системы частиц огнемета { DispatchParticleEffect( "flamethrower", PATTACH_POINT_FOLLOW, this, "muzzle" ); // Если нужно заменить зеленый огонь оранжевым, замени "flamethrower" на "flamethrower_orange". EmitSound( "Weapon_Immolator.Single" ); } break; case CREMATOR_AE_IMMO_PARTICLEOFF: // Маркер для отключения системы частиц огнемета { StopParticleEffects( this ); StopSound( "Weapon_Immolator.Single" ); EmitSound( "Weapon_Immolator.Stop" ); } break; case CREMATOR_AE_RELOAD: { ClearCondition( COND_CREMATOR_OUT_OF_AMMO ); ClearCondition( COND_NO_PRIMARY_AMMO ); m_iAmmo += 54; // Put your own int here. This defines for how long a cremator would be able to fire at an enemy. DevMsg( "AE_RELOAD\n" ); } break; case CREMATOR_AE_THROWGRENADE: // Маркер для броска гранаты { DevMsg( "Throwing incendiary grenade!\n" ); ThrowIncendiaryGrenade(); if( g_pGameRules->IsSkillLevel(SKILL_EASY) ) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 15.0f, 30.0f ); } else if( g_pGameRules->IsSkillLevel(SKILL_HARD) ) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 5.0f, 10.0f ); } else if (g_pGameRules->IsSkillLevel(SKILL_VERYHARD)) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat(3.0f, 5.0f); } else if (g_pGameRules->IsSkillLevel(SKILL_NIGHTMARE)) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat(1.0f, 3.0f); } else { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 10.0f, 20.0f ); } } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
void CHL1NPCTalker::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HL1TALKER_FOLLOW_WALK_PATH_FOR_UNITS: { float distance; distance = (m_vecLastPosition - GetLocalOrigin()).Length2D(); // Walk path until far enough away if ( distance > pTask->flTaskData || GetNavigator()->GetGoalType() == GOALTYPE_NONE ) { TaskComplete(); GetNavigator()->ClearGoal(); // Stop moving } break; } case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); // track head to the client for a while. if ( m_NPCState == NPC_STATE_IDLE && !IsMoving() && !GetExpresser()->IsSpeaking() ) { if ( pPlayer ) { IdleHeadTurn( pPlayer ); } } else { // started moving or talking TaskFail( "moved away" ); return; } if ( pTask->iTask == TASK_TALKER_CLIENT_STARE ) { // fail out if the player looks away or moves away. if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() > TALKER_STARE_DIST ) { // player moved away. TaskFail( NO_TASK_FAILURE ); } Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); if ( UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), vForward ) < m_flFieldOfView ) { // player looked away TaskFail( "looked away" ); } } if ( gpGlobals->curtime > m_flWaitFinished ) { TaskComplete( NO_TASK_FAILURE ); } break; } case TASK_WAIT_FOR_MOVEMENT: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT(at_console, "walking, talking\n"); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() ) { IdleHeadTurn( GetEnemy() ); } BaseClass::RunTask( pTask ); break; } case TASK_FACE_PLAYER: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); if ( pPlayer ) { //GetMotor()->SetIdealYaw( pPlayer->GetAbsOrigin() ); IdleHeadTurn( pPlayer ); if ( gpGlobals->curtime > m_flWaitFinished && GetMotor()->DeltaIdealYaw() < 10 ) { TaskComplete(); } } else { TaskFail( FAIL_NO_PLAYER ); } break; } case TASK_TALKER_EYECONTACT: { if (!IsMoving() && GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } BaseClass::RunTask( pTask ); break; } default: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() && m_NPCState == NPC_STATE_COMBAT ) { IdleHeadTurn( GetEnemy() ); } else if ( GetFollowTarget() ) { IdleHeadTurn( GetFollowTarget() ); } BaseClass::RunTask( pTask ); break; } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CNPC_Bug_Builder::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_BBUG_GET_PATH_TO_FLEE: { // Always tell our bughole that we're under attack if ( m_hMyBugHole ) { m_hMyBugHole->IncomingFleeingBug( this ); } // If we have no squad, or we couldn't get a path to our squadmate, move to our bughole if ( m_hMyBugHole ) { SetTarget( m_hMyBugHole ); AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN ); if ( GetNavigator()->SetGoal( goal ) ) { TaskComplete(); return; } } TaskComplete(); } break; case TASK_BBUG_GET_PATH_TO_BUGHOLE: { // Get a path back to my bughole // If we have no squad, or we couldn't get a path to our squadmate, look for a bughole if ( m_hMyBugHole ) { SetTarget( m_hMyBugHole ); AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN ); if ( GetNavigator()->SetGoal( goal ) ) { TaskComplete(); return; } } TaskFail( "Couldn't get to bughole." ); } break; case TASK_BBUG_HOLE_REMOVE: { TaskComplete(); // Crawl inside the bughole and remove myself AddEffects( EF_NODRAW ); AddSolidFlags( FSOLID_NOT_SOLID ); Event_Killed( CTakeDamageInfo( this, this, 200, DMG_CRUSH ) ); // Tell the bughole if ( m_hMyBugHole ) { m_hMyBugHole->BugReturned(); } } break; case TASK_BBUG_GET_PATH_TO_DAWDLE: { // Get a dawdle point ahead of us Vector vecForward, vecTarget; AngleVectors( GetAbsAngles(), &vecForward ); VectorMA( GetAbsOrigin(), random->RandomFloat( DAWDLE_MIN_DIST, DAWDLE_MAX_DIST ), vecForward, vecTarget ); // See how far we could move ahead trace_t tr; UTIL_TraceEntity( this, GetAbsOrigin(), vecTarget, MASK_SOLID, &tr); float flDistance = tr.fraction * (vecTarget - GetAbsOrigin()).Length(); if ( flDistance >= DAWDLE_MIN_DIST ) { AI_NavGoal_t goal( tr.endpos ); GetNavigator()->SetGoal( goal ); } TaskComplete(); } break; case TASK_BBUG_FACE_DAWDLE: { // Turn a random amount to the right float flYaw = GetMotor()->GetIdealYaw(); flYaw = flYaw + random->RandomFloat( 45, 135 ); GetMotor()->SetIdealYaw( UTIL_AngleMod(flYaw) ); SetTurnActivity(); break; } break; default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Input : pTask - //----------------------------------------------------------------------------- void CNPC_Crow::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { // // This task enables us to build a path that requires flight. // // case TASK_CROW_PREPARE_TO_FLY: // { // SetFlyingState( FlyState_Flying ); // TaskComplete(); // break; // } case TASK_CROW_TAKEOFF: { if ( random->RandomInt( 1, 4 ) == 1 ) { AlertSound(); } FlapSound(); SetIdealActivity( ( Activity )ACT_CROW_TAKEOFF ); break; } case TASK_CROW_PICK_EVADE_GOAL: { if ( GetEnemy() != NULL ) { // // Get our enemy's position in x/y. // Vector vecEnemyOrigin = GetEnemy()->GetAbsOrigin(); vecEnemyOrigin.z = GetAbsOrigin().z; // // Pick a hop goal a random distance along a vector away from our enemy. // m_vSavePosition = GetAbsOrigin() - vecEnemyOrigin; VectorNormalize( m_vSavePosition ); m_vSavePosition = GetAbsOrigin() + m_vSavePosition * ( 32 + random->RandomInt( 0, 32 ) ); GetMotor()->SetIdealYawToTarget( m_vSavePosition ); TaskComplete(); } else { TaskFail( "No enemy" ); } break; } case TASK_CROW_FALL_TO_GROUND: { SetFlyingState( FlyState_Falling ); break; } case TASK_FIND_HINTNODE: { if ( GetGoalEnt() ) { TaskComplete(); return; } // Overloaded because we search over a greater distance. if ( !GetHintNode() ) { SetHintNode(CAI_HintManager::FindHint( this, HINT_CROW_FLYTO_POINT, bits_HINT_NODE_NEAREST | bits_HINT_NODE_USE_GROUP, 10000 )); } if ( GetHintNode() ) { TaskComplete(); } else { TaskFail( FAIL_NO_HINT_NODE ); } break; } case TASK_GET_PATH_TO_HINTNODE: { //How did this happen?! if ( GetGoalEnt() == this ) { SetGoalEnt( NULL ); } if ( GetGoalEnt() ) { SetFlyingState( FlyState_Flying ); StartTargetHandling( GetGoalEnt() ); m_bReachedMoveGoal = false; TaskComplete(); SetHintNode( NULL ); return; } if ( GetHintNode() ) { Vector vHintPos; GetHintNode()->GetPosition(this, &vHintPos); SetNavType( NAV_FLY ); CapabilitiesAdd( bits_CAP_MOVE_FLY ); if ( !GetNavigator()->SetGoal( vHintPos ) ) SetHintNode(NULL); CapabilitiesRemove( bits_CAP_MOVE_FLY ); } if ( GetHintNode() ) { m_bReachedMoveGoal = false; TaskComplete(); } else { TaskFail( FAIL_NO_ROUTE ); } break; } // // We have failed to fly normally. Pick a random "up" direction and fly that way. // case TASK_CROW_FLY: { float flYaw = UTIL_AngleMod( random->RandomInt( -180, 180 ) ); Vector vecNewVelocity( cos( DEG2RAD( flYaw ) ), sin( DEG2RAD( flYaw ) ), random->RandomFloat( 0.1f, 0.5f ) ); vecNewVelocity *= CROW_AIRSPEED; SetAbsVelocity( vecNewVelocity ); SetIdealActivity( ACT_FLY ); m_bSoar = false; m_flSoarTime = gpGlobals->curtime + random->RandomFloat( 2, 5 ); break; } case TASK_CROW_PICK_RANDOM_GOAL: { m_vSavePosition = GetLocalOrigin() + Vector( random->RandomFloat( -48.0f, 48.0f ), random->RandomFloat( -48.0f, 48.0f ), 0 ); TaskComplete(); break; } case TASK_CROW_HOP: { SetIdealActivity( ACT_HOP ); m_flHopStartZ = GetLocalOrigin().z; break; } case TASK_CROW_WAIT_FOR_BARNACLE_KILL: { break; } default: { BaseClass::StartTask( pTask ); } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_PolicingBehavior::StartTask( const Task_t *pTask ) { switch (pTask->iTask) { case TASK_POLICE_GET_PATH_TO_HARASS_GOAL: { Vector harassDir = ( m_hPoliceGoal->GetTarget()->WorldSpaceCenter() - WorldSpaceCenter() ); float flDist = VectorNormalize( harassDir ); // See if we're already close enough if ( flDist < pTask->flTaskData ) { TaskComplete(); break; } float flInter1, flInter2; Vector harassPos = GetAbsOrigin() + ( harassDir * ( flDist - pTask->flTaskData ) ); // Find a point on our policing radius to stand on if ( IntersectInfiniteRayWithSphere( GetAbsOrigin(), harassDir, m_hPoliceGoal->GetAbsOrigin(), m_hPoliceGoal->GetRadius(), &flInter1, &flInter2 ) ) { Vector vPos = m_hPoliceGoal->GetAbsOrigin() + harassDir * ( MAX( flInter1, flInter2 ) ); // See how far away the default one is float testDist = UTIL_DistApprox2D( m_hPoliceGoal->GetAbsOrigin(), harassPos ); // If our other goal is closer, choose it if ( testDist > UTIL_DistApprox2D( m_hPoliceGoal->GetAbsOrigin(), vPos ) ) { harassPos = vPos; } } if ( GetNavigator()->SetGoal( harassPos, (int)pTask->flTaskData ) ) { GetNavigator()->SetMovementActivity( (Activity) ACT_WALK_ANGRY ); GetNavigator()->SetArrivalDirection( m_hPoliceGoal->GetTarget() ); TaskComplete(); } else { TaskFail( FAIL_NO_ROUTE ); } } break; case TASK_POLICE_GET_PATH_TO_POLICE_GOAL: { if ( GetNavigator()->SetGoal( m_hPoliceGoal->GetAbsOrigin(), (int)pTask->flTaskData ) ) { GetNavigator()->SetArrivalDirection( m_hPoliceGoal->GetAbsAngles() ); TaskComplete(); } else { TaskFail( FAIL_NO_ROUTE ); } } break; case TASK_POLICE_ANNOUNCE_HARASS: { AnnouncePolicing(); // Randomly say this again in the future m_flNextHarassTime = gpGlobals->curtime + random->RandomInt( 4, 6 ); // Scatter rubber-neckers CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), 256, 2.0f, GetOuter() ); } TaskComplete(); break; case TASK_POLICE_FACE_ALONG_GOAL: { // We may have lost our police goal in the 2 seconds we wait before this task if ( m_hPoliceGoal ) { GetMotor()->SetIdealYaw( m_hPoliceGoal->GetAbsAngles().y ); GetOuter()->SetTurnActivity(); } } break; default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Input : pTask - //----------------------------------------------------------------------------- void CNPC_Crow::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CROW_TAKEOFF: { if ( GetNavigator()->IsGoalActive() ) { GetMotor()->SetIdealYawToTargetAndUpdate( GetAbsOrigin() + GetNavigator()->GetCurWaypointPos(), AI_KEEP_YAW_SPEED ); } else TaskFail( FAIL_NO_ROUTE ); if ( IsActivityFinished() ) { TaskComplete(); SetIdealActivity( ACT_FLY ); m_bSoar = false; m_flSoarTime = gpGlobals->curtime + random->RandomFloat( 2, 5 ); } break; } case TASK_CROW_HOP: { if ( IsActivityFinished() ) { TaskComplete(); SetIdealActivity( ACT_IDLE ); } if ( ( GetAbsOrigin().z < m_flHopStartZ ) && ( !( GetFlags() & FL_ONGROUND ) ) ) { // // We've hopped off of something! See if we're going to fall very far. // trace_t tr; AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, -32 ), MASK_SOLID, this, HL2COLLISION_GROUP_CROW, &tr ); if ( tr.fraction == 1.0f ) { // // We're falling! Better fly away. SelectSchedule will check ONGROUND and do the right thing. // TaskComplete(); } else { // // We'll be okay. Don't check again unless what we're hopping onto moves // out from under us. // m_flHopStartZ = GetAbsOrigin().z - ( 32 * tr.fraction ); } } break; } // // Face the direction we are flying. // case TASK_CROW_FLY: { GetMotor()->SetIdealYawToTargetAndUpdate( GetAbsOrigin() + GetAbsVelocity(), AI_KEEP_YAW_SPEED ); break; } case TASK_CROW_FALL_TO_GROUND: { if ( GetFlags() & FL_ONGROUND ) { SetFlyingState( FlyState_Walking ); TaskComplete(); } break; } case TASK_CROW_WAIT_FOR_BARNACLE_KILL: { if ( m_flNextFlinchTime < gpGlobals->curtime ) { m_flNextFlinchTime = gpGlobals->curtime + random->RandomFloat( 0.5f, 2.0f ); // dvs: TODO: squirm // dvs: TODO: spawn feathers EmitSound( "NPC_Crow.Squawk" ); } break; } default: { CAI_BaseNPC::RunTask( pTask ); } } }
//----------------------------------------------------------------------------- // Purpose: Determines the pose parameters for the bending of the body and tail speed // Input : moveRel - the dot products for the deviation off of each direction (f,r,u) // speed - speed of the fish //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::SetPoses( Vector moveRel, float speed ) { float movePerc, moveBase; //Find out how fast we're moving in our animations boundaries if ( GetIdealActivity() == ACT_WALK ) { moveBase = 0.5f; movePerc = moveBase * ( speed / ICH_SWIM_SPEED_WALK ); } else { moveBase = 1.0f; movePerc = moveBase * ( speed / ICH_SWIM_SPEED_RUN ); } Vector tailPosition; float flSwimSpeed = movePerc; //Forward deviation if ( moveRel.x > 0 ) { flSwimSpeed *= moveBase + (( moveRel.x / m_vecAccelerationMax.x )*moveBase); } else if ( moveRel.x < 0 ) { flSwimSpeed *= moveBase - (( moveRel.x / m_vecAccelerationMin.x )*moveBase); } //Vertical deviation if ( moveRel.z > 0 ) { tailPosition[PITCH] = -90.0f * ( moveRel.z / m_vecAccelerationMax.z ); } else if ( moveRel.z < 0 ) { tailPosition[PITCH] = 90.0f * ( moveRel.z / m_vecAccelerationMin.z ); } else { tailPosition[PITCH] = 0.0f; } //Lateral deviation if ( moveRel.y > 0 ) { tailPosition[ROLL] = 25 * moveRel.y / m_vecAccelerationMax.y; tailPosition[YAW] = -1.0f * moveRel.y / m_vecAccelerationMax.y; } else if ( moveRel.y < 0 ) { tailPosition[ROLL] = -25 * moveRel.y / m_vecAccelerationMin.y; tailPosition[YAW] = moveRel.y / m_vecAccelerationMin.y; } else { tailPosition[ROLL] = 0.0f; tailPosition[YAW] = 0.0f; } //Clamp flSwimSpeed = clamp( flSwimSpeed, 0.25f, 1.0f ); tailPosition[YAW] = clamp( tailPosition[YAW], -90.0f, 90.0f ); tailPosition[PITCH] = clamp( tailPosition[PITCH], -90.0f, 90.0f ); //Blend m_flTailYaw = ( m_flTailYaw * 0.8f ) + ( tailPosition[YAW] * 0.2f ); m_flTailPitch = ( m_flTailPitch * 0.8f ) + ( tailPosition[PITCH] * 0.2f ); m_flSwimSpeed = ( m_flSwimSpeed * 0.8f ) + ( flSwimSpeed * 0.2f ); //Pose the body SetPoseParameter( 0, m_flSwimSpeed ); SetPoseParameter( 1, m_flTailYaw ); SetPoseParameter( 2, m_flTailPitch ); //FIXME: Until the sequence info is reset properly after SetPoseParameter if ( ( GetActivity() == ACT_RUN ) || ( GetActivity() == ACT_WALK ) ) { ResetSequenceInfo(); } //Face our current velocity GetMotor()->SetIdealYawAndUpdate( UTIL_AngleMod( CalcIdealYaw( GetAbsOrigin() + GetAbsVelocity() ) ), AI_KEEP_YAW_SPEED ); float pitch = 0.0f; if ( speed != 0.0f ) { pitch = -RAD2DEG( asin( GetAbsVelocity().z / speed ) ); } //FIXME: Framerate dependant QAngle angles = GetLocalAngles(); angles.x = (angles.x * 0.8f) + (pitch * 0.2f); angles.z = (angles.z * 0.9f) + (tailPosition[ROLL] * 0.1f); SetLocalAngles( angles ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_FuncTankBehavior::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_FUNCTANK_ANNOUNCE_SCAN: { if ( random->RandomInt( 0, 3 ) == 0 ) { GetOuter()->SpeakSentence( FUNCTANK_SENTENCE_SCAN_FOR_ENEMIES ); } TaskComplete(); } break; case TASK_GET_PATH_TO_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } Vector vecManPos; m_hFuncTank->NPC_FindManPoint( vecManPos ); AI_NavGoal_t goal( vecManPos ); goal.pTarget = m_hFuncTank; if ( GetNavigator()->SetGoal( goal ) ) { GetNavigator()->SetArrivalDirection( m_hFuncTank->GetAbsAngles() ); TaskComplete(); } else { TaskFail("NO PATH"); // Don't try and use me again for a while SetBusy( gpGlobals->curtime + AI_FUNCTANK_BEHAVIOR_BUSYTIME ); } break; } case TASK_FACE_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } // Ensure we've reached the func_tank Vector vecManPos; m_hFuncTank->NPC_FindManPoint( vecManPos ); // More leniency in Z. Vector vecDelta = (vecManPos - GetAbsOrigin()); if ( fabs(vecDelta.x) > 16 || fabs(vecDelta.y) > 16 || fabs(vecDelta.z) > 48 ) { TaskFail( "Not correctly on func_tank man point" ); m_hFuncTank->NPC_InterruptRoute(); return; } GetMotor()->SetIdealYawToTarget( m_hFuncTank->GetAbsOrigin() ); GetOuter()->SetTurnActivity(); break; } case TASK_HOLSTER_WEAPON: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } if ( GetOuter()->IsWeaponHolstered() || !GetOuter()->CanHolsterWeapon() ) { GetOuter()->SpeakSentence( FUNCTANK_SENTENCE_JUST_MOUNTED ); // We are at the correct position and facing for the func_tank, mount it. m_hFuncTank->StartControl( GetOuter() ); GetOuter()->ClearEnemyMemory(); m_bMounted = true; TaskComplete(); GetOuter()->SetIdealActivity( ACT_IDLE_MANNEDGUN ); } else { GetOuter()->SetDesiredWeaponState( DESIREDWEAPONSTATE_HOLSTERED ); } break; } case TASK_FIRE_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } GetOuter()->m_flWaitFinished = gpGlobals->curtime + FUNCTANK_FIRE_TIME; break; } case TASK_SCAN_LEFT_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } GetMotor()->SetIdealYawToTarget( m_hFuncTank->GetAbsOrigin() ); float flCenterYaw = m_hFuncTank->YawCenterWorld(); float flYawRange = m_hFuncTank->YawRange(); float flScanAmount = random->RandomFloat( 0, flYawRange ); QAngle vecTargetAngles( 0, UTIL_AngleMod( flCenterYaw + flScanAmount ), 0 ); /* float flCenterPitch = m_hFuncTank->YawCenterWorld(); float flPitchRange = m_hFuncTank->PitchRange(); float flPitch = random->RandomFloat( -flPitchRange, flPitchRange ); QAngle vecTargetAngles( flCenterPitch + flPitch, UTIL_AngleMod( flCenterYaw + flScanAmount ), 0 ); */ Vector vecTargetForward; AngleVectors( vecTargetAngles, &vecTargetForward ); Vector vecTarget = GetOuter()->EyePosition() + (vecTargetForward * 256); GetOuter()->AddLookTarget( vecTarget, 1.0, 2.0, 0.2 ); m_hFuncTank->NPC_SetIdleAngle( vecTarget ); break; } case TASK_SCAN_RIGHT_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } GetMotor()->SetIdealYawToTarget( m_hFuncTank->GetAbsOrigin() ); float flCenterYaw = m_hFuncTank->YawCenterWorld(); float flYawRange = m_hFuncTank->YawRange(); float flScanAmount = random->RandomFloat( 0, flYawRange ); QAngle vecTargetAngles( 0, UTIL_AngleMod( flCenterYaw - flScanAmount ), 0 ); /* float flCenterPitch = m_hFuncTank->YawCenterWorld(); float flPitchRange = m_hFuncTank->PitchRange(); float flPitch = random->RandomFloat( -flPitchRange, flPitchRange ); QAngle vecTargetAngles( flCenterPitch + flPitch, UTIL_AngleMod( flCenterYaw - flScanAmount ), 0 ); */ Vector vecTargetForward; AngleVectors( vecTargetAngles, &vecTargetForward ); Vector vecTarget = GetOuter()->EyePosition() + (vecTargetForward * 256); GetOuter()->AddLookTarget( vecTarget, 1.0, 2.0, 0.2 ); m_hFuncTank->NPC_SetIdleAngle( vecTarget ); break; } case TASK_FORGET_ABOUT_FUNCTANK: { if ( !m_hFuncTank ) { TaskFail( FAIL_NO_TARGET ); return; } break; } default: { BaseClass::StartTask( pTask ); break; } } }