//------------------------------------------------------------------------------ // Purpose: routine called to start when a task initially starts // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_PrepareToEngageBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_PREPARE_TO_ENGAGE: { CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy == NULL ) { TaskFail( FAIL_NO_ENEMY ); return; } if ( GetPrepareToAttackPath( GetEnemy()->GetAbsOrigin() ) ) { TaskComplete(); } else { // TODO: wander to a random nearby spot TaskFail( FAIL_NO_ROUTE ); } return; } default: BaseClass::StartTask( pTask ); break; } }
void CAI_PlayerAlly::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: if ( pTask->iTask == TASK_TALKER_CLIENT_STARE ) { // Get edict for one player CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( engine->PEntityOfEntIndex( 1 ) ); Assert( pPlayer ); // fail out if the player looks away or moves away. if ( ( pPlayer->GetLocalOrigin() - GetLocalOrigin() ).Length2D() > TLK_STARE_DIST ) { // player moved away. TaskFail("Player moved away"); } Vector forward; AngleVectors( pPlayer->GetLocalAngles(), &forward ); if ( UTIL_DotPoints( pPlayer->GetLocalOrigin(), GetLocalOrigin(), forward ) < m_flFieldOfView ) { // player looked away TaskFail("Player looked away"); } } if ( gpGlobals->curtime > m_flWaitFinished ) { TaskComplete(); } break; case TASK_TALKER_EYECONTACT: if (IsMoving() || !GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: if (!GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { // override so that during walk, a scientist may talk and greet player FIdleHello(); if (random->RandomInt(0,m_nSpeak * 20) == 0) { FIdleSpeak(); } } BaseClass::RunTask( pTask ); break; default: BaseClass::RunTask( pTask ); } }
void CNPCSimpleTalker::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_TALKER_WAIT_FOR_SEMAPHORE: if ( GetExpresser()->SemaphoreIsAvailable( this ) ) TaskComplete(); break; case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: if ( pTask->iTask == TASK_TALKER_CLIENT_STARE && AI_IsSinglePlayer() ) { // Get edict for one player CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); Assert( pPlayer ); // fail out if the player looks away or moves away. if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() > TALKER_STARE_DIST ) { // player moved away. TaskFail("Player moved away"); } Vector forward; AngleVectors( pPlayer->GetLocalAngles(), &forward ); if ( UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), forward ) < m_flFieldOfView ) { // player looked away TaskFail("Player looked away"); } } if ( IsWaitFinished() ) { TaskComplete(); } break; case TASK_TALKER_EYECONTACT: if (IsMoving() || !GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: FIdleSpeakWhileMoving(); BaseClass::RunTask( pTask ); break; default: BaseClass::RunTask( pTask ); } }
void CRebelZombie::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_ZOMBIE_EXPRESS_ANGER: { if ( random->RandomInt( 1, 4 ) == 2 ) { SetIdealActivity( (Activity)ACT_REBEL_ZOMBIE_TANTRUM ); } else { TaskComplete(); } break; } case TASK_ZOMBIE_YAW_TO_DOOR: { AssertMsg( m_hBlockingDoor != NULL, "Expected condition handling to break schedule before landing here" ); if ( m_hBlockingDoor != NULL ) { GetMotor()->SetIdealYaw( m_flDoorBashYaw ); } TaskComplete(); break; } case TASK_ZOMBIE_ATTACK_DOOR: { m_DurationDoorBash.Reset(); SetIdealActivity( SelectDoorBash() ); break; } case TASK_ZOMBIE_CHARGE_ENEMY: { if ( !GetEnemy() ) TaskFail( FAIL_NO_ENEMY ); else if ( GetNavigator()->SetVectorGoalFromTarget( GetEnemy()->GetLocalOrigin() ) ) { m_vPositionCharged = GetEnemy()->GetLocalOrigin(); TaskComplete(); } else TaskFail( FAIL_NO_ROUTE ); break; } default: BaseClass::StartTask( pTask ); break; } }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CAI_BasePhysicsFlyingBot::StartTask( const Task_t *pTask ) { switch (pTask->iTask) { // Skip as done via bone controller case TASK_FACE_ENEMY: { TaskComplete(); break; } // Activity is just idle (have no run) case TASK_RUN_PATH: { GetNavigator()->SetMovementActivity(ACT_IDLE); TaskComplete(); break; } // Don't check for run/walk activity case TASK_SCRIPT_RUN_TO_TARGET: case TASK_SCRIPT_WALK_TO_TARGET: { if (GetTarget() == NULL) { TaskFail(FAIL_NO_TARGET); } else { if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) ) { TaskFail(FAIL_NO_ROUTE); GetNavigator()->ClearGoal(); } } TaskComplete(); break; } // Override to get more to get a directional path case TASK_GET_PATH_TO_RANDOM_NODE: { if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) ) TaskComplete(); else TaskFail(FAIL_NO_REACHABLE_NODE); break; } default: { BaseClass::StartTask(pTask); } } }
//========================================================= // StartTask //========================================================= void CController :: StartTask ( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_RANGE_ATTACK1: CSquadMonster :: StartTask ( pTask ); break; case TASK_GET_PATH_TO_ENEMY_LKP: { if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, pTask->flData, (m_vecEnemyLKP - pev->origin).Length() + 1024 )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY: { CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy == NULL ) { TaskFail(); return; } if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, (pEnemy->pev->origin - pev->origin).Length() + 1024 )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } default: CSquadMonster :: StartTask ( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_ICH_THRASH_PATH: GetNavigator()->SetMovementActivity( (Activity) ACT_ICH_THRASH ); TaskComplete(); break; case TASK_ICH_GET_PATH_TO_RANDOM_NODE: { if ( GetEnemy() == NULL || !GetNavigator()->SetRandomGoal( GetEnemy()->GetLocalOrigin(), pTask->flTaskData ) ) { if (!GetNavigator()->SetRandomGoal( pTask->flTaskData ) ) { TaskFail(FAIL_NO_REACHABLE_NODE); return; } } TaskComplete(); } break; case TASK_ICH_GET_PATH_TO_DROWN_NODE: { Vector drownPos = GetLocalOrigin() - Vector( 0, 0, pTask->flTaskData ); if ( GetNavigator()->SetGoal( drownPos, AIN_CLEAR_TARGET ) == false ) { TaskFail( FAIL_NO_ROUTE ); return; } TaskComplete(); } break; case TASK_MELEE_ATTACK1: m_flPlaybackRate = 1.0f; BaseClass::StartTask(pTask); break; default: BaseClass::StartTask(pTask); break; } }
void CController :: StartTask ( const Task_t& task ) { switch ( task.iTask ) { case TASK_RANGE_ATTACK1: CSquadMonster :: StartTask ( task ); break; case TASK_GET_PATH_TO_ENEMY_LKP: { if (BuildNearestRoute( m_vecEnemyLKP, GetViewOffset(), task.flData, (m_vecEnemyLKP - GetAbsOrigin()).Length() + 1024 )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY: { CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy == NULL ) { TaskFail(); return; } if (BuildNearestRoute( pEnemy->GetAbsOrigin(), pEnemy->GetViewOffset(), task.flData, (pEnemy->GetAbsOrigin() - GetAbsOrigin()).Length() + 1024 )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } default: CSquadMonster :: StartTask ( task ); break; } }
//----------------------------------------------------------------------------- // TASK_RANGE_ATTACK1 //----------------------------------------------------------------------------- void CAI_BaseHumanoid::StartTaskRangeAttack1( const Task_t *pTask ) { if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 ) { BaseClass::StartTask( pTask ); return; } // Can't shoot if we're in the rest interval; fail the schedule if ( GetShotRegulator()->IsInRestInterval() ) { TaskFail( "Shot regulator in rest interval" ); return; } if ( GetShotRegulator()->ShouldShoot() ) { OnRangeAttack1(); ResetIdealActivity( ACT_RANGE_ATTACK1 ); } else { // This can happen if we start while in the middle of a burst // which shouldn't happen, but given the chaotic nature of our AI system, // does occasionally happen. ResetIdealActivity( ACT_IDLE_ANGRY ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_BehaviorAlyxInjured::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FIND_COVER_FROM_ENEMY: { CBaseEntity *pLeader = GetFollowTarget(); if ( !pLeader ) { BaseClass::StartTask( pTask ); break; } // Find a position behind our follow target Vector coverPos = vec3_invalid; if ( FindCoverFromEnemyBehindTarget( pLeader, COVER_DISTANCE, &coverPos ) ) { AI_NavGoal_t goal( GOALTYPE_LOCATION, coverPos, ACT_RUN, AIN_HULL_TOLERANCE, AIN_DEF_FLAGS ); GetOuter()->GetNavigator()->SetGoal( goal ); GetOuter()->m_flMoveWaitFinished = gpGlobals->curtime + pTask->flTaskData; TaskComplete(); return; } // Couldn't find anything TaskFail( FAIL_NO_COVER ); break; } default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // // // Output : //----------------------------------------------------------------------------- void CNPC_RollerDozer::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_ROLLERDOZER_GET_PATH_TO_CLEANUP_POINT: if ( GetNavigator()->SetGoal( m_vecCleanupPoint, AIN_CLEAR_TARGET ) ) { TaskComplete(); } else { // no way to get there TaskFail(FAIL_NO_ROUTE); } break; case TASK_ROLLERDOZER_CLEAR_DEBRIS: GetNavigator()->ClearGoal(); m_flWaitFinished = gpGlobals->curtime + 5; break; case TASK_ROLLERDOZER_FIND_CLEANUP_NODE: break; default: BaseClass::StartTask( pTask ); break; } }
//------------------------------------------------------------------------------ // Purpose: routine called to start when a task initially starts // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_HealOtherBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_HEAL_OTHER_FIND_TARGET: { if ( m_hHealTargetEnt ) { AI_NavGoal_t goal( GOALTYPE_TARGETENT, ACT_RUN, m_flApproachDistance, AIN_YAW_TO_DEST | AIN_UPDATE_TARGET_POS, m_hHealTargetEnt ); SetTarget( m_hHealTargetEnt ); GetNavigator()->SetArrivalDistance( m_flApproachDistance ); GetNavigator()->SetGoal( goal ); } else { TaskFail( FAIL_NO_TARGET ); m_flDeferUntil = gpGlobals->curtime + 3.0f; } break; } case TASK_HEAL_OTHER_MOVE_TO_TARGET: { break; } default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: Checks the validity of the given route's goaltype // Input : // Output : //----------------------------------------------------------------------------- bool CAI_BaseNPC::ValidateNavGoal() { if (GetNavigator()->GetGoalType() == GOALTYPE_COVER) { // Check if this location will block my enemy's line of sight to me if (GetEnemy()) { Activity nCoverActivity = GetCoverActivity( GetHintNode() ); Vector vCoverLocation = GetNavigator()->GetGoalPos(); // For now we have to drop the node to the floor so we can // get an accurate postion of the NPC. Should change once Ken checks in float floorZ = GetFloorZ(vCoverLocation); vCoverLocation.z = floorZ; Vector vEyePos = vCoverLocation + EyeOffset(nCoverActivity); if (!IsCoverPosition( GetEnemy()->EyePosition(), vEyePos ) ) { //Msg("BADUGI\n"); TaskFail(FAIL_BAD_PATH_GOAL); return false; } } } //Msg("BADUGI\n"); return true; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CNPC_WpnScanner::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_WPNSCANNER_ATTACK: { CBaseEntity *pEnemy = GetEnemy(); if ( !pEnemy ) { TaskFail( FAIL_NO_ENEMY ); return; } if ( m_flNextAttack > gpGlobals->curtime ) return; m_flNextAttack = gpGlobals->curtime + 0.2; Vector vecFirePos; QAngle vecAngles; GetAttachment( m_iMuzzleAttachment, vecFirePos, vecAngles ); Vector vecTarget = GetEnemy()->BodyTarget( vecFirePos ); Vector vecToTarget = (vecTarget - vecFirePos); VectorNormalize( vecToTarget ); VectorAngles( vecToTarget, vecAngles ); Vector vecRight; Vector vecUp; AngleVectors( vecAngles, &vecToTarget, &vecRight, &vecUp ); // Add some inaccuracy float x, y, z; do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); vecToTarget = vecToTarget + x * VECTOR_CONE_20DEGREES * vecRight + y * VECTOR_CONE_20DEGREES * vecUp; vecToTarget *= sk_wpnscanner_proj_speed.GetFloat(); baseprojectilecreate_t newProj; newProj.vecOrigin = vecFirePos; newProj.vecVelocity = vecToTarget; newProj.pOwner = this; newProj.iszModel = m_iszProjectileModel; newProj.flDamage = sk_wpnscanner_proj_dmg.GetFloat(); newProj.iDamageType = DMG_ENERGYBEAM; newProj.flDamageScale = 1.0; CBaseProjectile::Create( newProj ); break; } default: { BaseClass::RunTask(pTask); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_PassengerBehaviorZombie::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_FACE_HINTNODE: case TASK_FACE_LASTPOSITION: case TASK_FACE_SAVEPOSITION: case TASK_FACE_TARGET: case TASK_FACE_IDEAL: case TASK_FACE_SCRIPT: case TASK_FACE_PATH: TaskComplete(); break; case TASK_PASSENGER_ZOMBIE_RANGE_ATTACK1: break; case TASK_MELEE_ATTACK1: { // Only override this if we're "in" the vehicle if ( GetPassengerState() != PASSENGER_STATE_INSIDE ) { BaseClass::StartTask( pTask ); break; } // Swipe GetOuter()->SetIdealActivity( (Activity) ACT_PASSENGER_MELEE_ATTACK1 ); // Randomly attack again in the future float flWait = random->RandomFloat( 0.0f, 1.0f ); SuppressAttack( flWait ); } break; case TASK_PASSENGER_ZOMBIE_DISMOUNT: { // Start the process of dismounting from the vehicle StartDismount(); } break; case TASK_PASSENGER_ZOMBIE_ATTACH: { if ( AttachToVehicle() ) { TaskComplete(); return; } TaskFail( "Unable to attach to vehicle!" ); } break; default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: // // // Output : //----------------------------------------------------------------------------- void CNPC_RollerDozer::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_ROLLERDOZER_CLEAR_DEBRIS: if( gpGlobals->curtime > m_flWaitFinished ) { m_hDebris = NULL; m_flTimeDebrisSearch = gpGlobals->curtime; TaskComplete(); } else if( m_hDebris != NULL ) { float yaw = UTIL_VecToYaw( m_hDebris->GetLocalOrigin() - GetLocalOrigin() ); Vector vecRight, vecForward; AngleVectors( QAngle( 0, yaw, 0 ), &vecForward, &vecRight, NULL ); //Stop pushing if I'm going to push this object sideways or back towards the center of the cleanup area. Vector vecCleanupDir = m_hDebris->GetLocalOrigin() - m_vecCleanupPoint; VectorNormalize( vecCleanupDir ); if( DotProduct( vecForward, vecCleanupDir ) < -0.5 ) { // HACKHACK !!!HACKHACK - right now forcing an unstick. Do this better (sjb) // Clear the debris, suspend the search for debris, trick base class into unsticking me. m_hDebris = NULL; m_flTimeDebrisSearch = gpGlobals->curtime + 4; m_iFail = 10; TaskFail("Pushing Wrong Way"); } m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, ROLLERDOZER_FORWARD_SPEED * 2 ); } else { TaskFail("No debris!!"); } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: Handles movement towards the last move target. // Input : flInterval - //----------------------------------------------------------------------------- bool CNPC_Controller::OverridePathMove( float flInterval ) { CBaseEntity *pMoveTarget = (GetTarget()) ? GetTarget() : GetEnemy(); Vector waypointDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin(); float flWaypointDist = waypointDir.Length2D(); VectorNormalize(waypointDir); // cut corner? if (flWaypointDist < 128) { if (m_flGroundSpeed > 100) m_flGroundSpeed -= 40; } else { if (m_flGroundSpeed < 400) m_flGroundSpeed += 10; } m_velocity = m_velocity * 0.8 + m_flGroundSpeed * waypointDir * 0.5; SetAbsVelocity( m_velocity ); // ----------------------------------------------------------------- // Check route is blocked // ------------------------------------------------------------------ Vector checkPos = GetLocalOrigin() + (waypointDir * (m_flGroundSpeed * flInterval)); AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, GetLocalOrigin(), checkPos, MASK_NPCSOLID|CONTENTS_WATER, pMoveTarget, &moveTrace); if (IsMoveBlocked( moveTrace )) { TaskFail(FAIL_NO_ROUTE); GetNavigator()->ClearGoal(); return true; } // ---------------------------------------------- Vector lastPatrolDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin(); if ( ProgressFlyPath( flInterval, pMoveTarget, MASK_NPCSOLID, false, 64 ) == AINPP_COMPLETE ) { { m_vLastPatrolDir = lastPatrolDir; VectorNormalize(m_vLastPatrolDir); } return true; } return false; }
void CNPC_Stalker::UpdateAttackBeam( void ) { CBaseEntity *pEnemy = GetEnemy(); // If not burning at a target if (pEnemy) { if (gpGlobals->curtime > m_fBeamEndTime) { TaskComplete(); } else { Vector enemyLKP = GetEnemyLKP(); m_vLaserTargetPos = enemyLKP + pEnemy->GetViewOffset(); // Face my enemy GetMotor()->SetIdealYawToTargetAndUpdate( enemyLKP ); // --------------------------------------------- // Get beam end point // --------------------------------------------- Vector vecSrc = LaserStartPosition(GetAbsOrigin()); Vector targetDir = m_vLaserTargetPos - vecSrc; VectorNormalize(targetDir); // -------------------------------------------------------- // If beam position and laser dir are way off, end attack // -------------------------------------------------------- if ( DotProduct(targetDir,m_vLaserDir) < 0.5 ) { TaskComplete(); return; } trace_t tr; AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); // --------------------------------------------- // If beam not long enough, stop attacking // --------------------------------------------- if (tr.fraction == 1.0) { TaskComplete(); return; } CSoundEnt::InsertSound(SOUND_DANGER, tr.endpos, 60, 0.025, this); } } else { TaskFail(FAIL_NO_ENEMY); } }
//========================================================= // 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 CBullsquid :: StartTask ( Task_t *pTask ) { m_iTaskStatus = TASKSTATUS_RUNNING; switch ( pTask->iTask ) { case TASK_MELEE_ATTACK2: { switch ( RANDOM_LONG ( 0, 2 ) ) { case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); break; case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl2.wav", 1, ATTN_NORM ); break; case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); break; } CBaseMonster :: StartTask ( pTask ); break; } case TASK_SQUID_HOPTURN: { SetActivity ( ACT_HOP ); MakeIdealYaw ( m_vecEnemyLKP ); break; } case TASK_GET_PATH_TO_ENEMY: { if ( BuildRoute ( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) { m_iTaskStatus = TASKSTATUS_COMPLETE; } else { ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } default: { CBaseMonster :: StartTask ( pTask ); break; } } }
//------------------------------------------------------------------------------ // Purpose: routine called to start when a task initially starts // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_RangedAttackBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_RANGED_FIND_MISSILE_LOCATION: { if ( !FindFiringLocation() ) { m_flDeferUntil = gpGlobals->curtime + 1.0f; TaskFail( "Failed to FindFiringLocation" ); } else { // TODO: Fix this! // It's too late to fail here, as we've already picked this behavior and schedule. // If we're in a bad spot for firing, we need to detect it earlier and pick a behavior that will move us. // That behavior needs to be aware of bad firing spots too and factor that into its spot finding. // if ( !ValidateMissileLocation() ) // { // m_flDeferUntil = gpGlobals->curtime + 1.0f; // TaskFail( "Failed to ValidateMissileLocation" ); // } } break; } case TASK_RANGED_PREPARE_TO_FIRE: { GetOuter()->SetIdealActivity( ACT_PREP_TO_FIRE ); break; } case TASK_RANGED_FIRE: { GetOuter()->SetIdealActivity( ACT_FIRE ); break; } case TASK_RANGED_FIRE_RECOVER: { GetOuter()->SetIdealActivity( ACT_FIRE_RECOVER ); break; } default: BaseClass::StartTask( pTask ); break; } }
//========================================================= // RunTask //========================================================= void CBigMomma::RunTask( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_MOVE_TO_NODE_RANGE: { float distance; if ( m_hTargetEnt == NULL ) TaskFail(); else { distance = ( m_vecMoveGoal - pev->origin ).Length2D(); // Set the appropriate activity based on an overlapping range // overlap the range to prevent oscillation if ( (distance < GetNodeRange()) || MovementIsComplete() ) { ALERT( at_aiconsole, "BM: Reached node!\n" ); TaskComplete(); RouteClear(); // Stop moving } } } break; case TASK_WAIT_NODE: if ( m_hTargetEnt != NULL && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) return; if ( gpGlobals->time > m_flWaitFinished ) TaskComplete(); ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); break; case TASK_PLAY_NODE_PRESEQUENCE: case TASK_PLAY_NODE_SEQUENCE: if ( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); } break; default: CBaseMonster::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CAI_AssaultBehavior::GatherConditions( void ) { BaseClass::GatherConditions(); // If this NPC is moving towards an assault point which // a) Has a Next Assault Point, and // b) Is flagged to Clear On Arrival, // then hit and clear the assault point (fire all entity I/O) and move on to the next one without // interrupting the NPC's schedule. This provides a more fluid movement from point to point. if( IsCurSchedule( SCHED_MOVE_TO_ASSAULT_POINT ) && hl2_episodic.GetBool() ) { if( m_hAssaultPoint && m_hAssaultPoint->HasSpawnFlags(SF_ASSAULTPOINT_CLEARONARRIVAL) && m_hAssaultPoint->m_NextAssaultPointName != NULL_STRING ) { float flDist = GetAbsOrigin().DistTo( m_hAssaultPoint->GetAbsOrigin() ); if( flDist <= GetOuter()->GetMotor()->MinStoppingDist() ) { OnHitAssaultPoint(); ClearAssaultPoint(); AI_NavGoal_t goal( m_hAssaultPoint->GetAbsOrigin() ); goal.pTarget = m_hAssaultPoint; if ( GetNavigator()->SetGoal( goal ) == false ) { TaskFail( "Can't refresh assault path" ); } } } if( OnStrictAssault() ) { // Don't get distracted. Die trying if you have to. ClearCondition( COND_HEAR_DANGER ); } } if ( IsForcingCrouch() && GetOuter()->IsCrouching() ) { ClearCondition( COND_HEAR_BULLET_IMPACT ); } }
void CNPC_Hydra::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_HYDRA_DEPLOY: { m_flHeadGoalInfluence = 1.0; float dist = (EyePosition() - m_vecHeadGoal).Length(); if (dist < m_idealSegmentLength) { TaskComplete(); } AimHeadInTravelDirection( 0.2 ); } break; case TASK_HYDRA_PREP_STAB: { int i; if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } CBaseEntity *pTarget = GetTarget(); if (pTarget == NULL) { TaskFail( FAIL_NO_TARGET ); } if (pTarget->IsPlayer()) { m_vecTarget = pTarget->EyePosition( ); } else { m_vecTarget = pTarget->BodyTarget( EyePosition( ) ); } float distToTarget = (m_vecTarget - m_vecHeadGoal).Length(); float distToBase = (m_vecHeadGoal - GetAbsOrigin()).Length(); m_idealLength = distToTarget + distToBase * 0.5; if (m_idealLength > HYDRA_MAX_LENGTH) m_idealLength = HYDRA_MAX_LENGTH; if (distToTarget < 100.0) { m_vecTargetDir = (m_vecTarget - m_vecHeadGoal); VectorNormalize( m_vecTargetDir ); m_vecHeadGoal = m_vecHeadGoal - m_vecTargetDir * (100 - distToTarget) * 0.5; } else if (distToTarget > 200.0) { m_vecTargetDir = (m_vecTarget - m_vecHeadGoal); VectorNormalize( m_vecTargetDir ); m_vecHeadGoal = m_vecHeadGoal - m_vecTargetDir * (200.0 - distToTarget) * 0.5; } // face enemy m_vecTargetDir = (m_vecTarget - m_body[m_body.Count()-1].vecPos); VectorNormalize( m_vecTargetDir ); m_vecHeadDir = m_vecHeadDir * 0.6 + m_vecTargetDir * 0.4; VectorNormalize( m_vecHeadDir.GetForModify() ); // build tension towards strike time float influence = 1.0 - (m_flTaskEndTime - gpGlobals->curtime) / pTask->flTaskData; if (influence > 1) influence = 1.0; influence = influence * influence * influence; m_flHeadGoalInfluence = influence; // keep head segment straight i = m_body.Count() - 2; m_body[i].vecGoalPos = m_vecHeadGoal - m_vecHeadDir * m_body[i].flActualLength; m_body[i].flGoalInfluence = influence; // curve neck into spiral float distBackFromHead = m_body[i].flActualLength; Vector right, up; VectorVectors( m_vecHeadDir, right, up ); for (i = i - 1; i > 1 && distBackFromHead < distToTarget; i--) { distBackFromHead += m_body[i].flActualLength; float r = (distBackFromHead / 200) * 3.1415 * 2; // spiral Vector p0 = m_vecHeadGoal - m_vecHeadDir * distBackFromHead * 0.5 + cos( r ) * m_body[i].flActualLength * right + sin( r ) * m_body[i].flActualLength * up; // base r = (distBackFromHead / m_idealLength) * 3.1415 * 0.2; r = sin( r ); p0 = p0 * (1 - r) + r * GetAbsOrigin(); m_body[i].vecGoalPos = p0; m_body[i].flGoalInfluence = influence * (1.0 - (distBackFromHead / distToTarget)); /* if ( (pEnemy->EyePosition( ) - m_body[i].vecPos).Length() < distBackFromHead) { if ( gpGlobals->curtime - m_flLastAttackTime > 4.0) { TaskComplete(); } return; } */ } // look to see if any of the goal positions are stuck for (i = i; i < m_body.Count() - 1; i++) { if (m_body[i].bStuck) { Vector delta = DotProduct( m_body[i].vecGoalPos - m_body[i].vecPos, m_vecHeadDir) * m_vecHeadDir; m_vecHeadGoal -= delta * m_body[i].flGoalInfluence; break; } } if ( gpGlobals->curtime >= m_flTaskEndTime ) { if (distToTarget < 500) { TaskComplete( ); return; } else { TaskFail( "target is too far away" ); return; } } } return; case TASK_HYDRA_STAB: { int i; if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } if (m_flTaskEndTime <= gpGlobals->curtime) { TaskComplete( ); return; } m_flHeadGoalInfluence = 1.0; // face enemy //m_vecHeadDir = (pEnemy->EyePosition( ) - m_body[m_body.Count()-1].vecPos); //VectorNormalize( m_vecHeadDir.GetForModify() ); // keep head segment straight i = m_body.Count() - 2; m_body[i].vecGoalPos = m_vecHeadGoal + m_vecHeadDir * m_body[i].flActualLength; m_body[i].flGoalInfluence = 1.0; Vector vecToTarget = (m_vecTarget - EyePosition( )); // check to see if we went past target if (DotProduct( vecToTarget, m_vecHeadDir ) < 0.0) { TaskComplete( ); return; } float distToTarget = vecToTarget.Length(); float distToBase = (EyePosition( ) - GetAbsOrigin()).Length(); m_idealLength = distToTarget + distToBase; /* if (distToTarget < 20) { m_vecHeadGoal = m_vecTarget; SetLastAttackTime( gpGlobals->curtime ); TaskComplete(); return; } else */ { // hit enemy m_vecHeadGoal = m_vecTarget + m_vecHeadDir * 300; } if (m_idealLength > HYDRA_MAX_LENGTH) m_idealLength = HYDRA_MAX_LENGTH; // curve neck into spiral float distBackFromHead = m_body[i].flActualLength; Vector right, up; VectorVectors( m_vecHeadDir, right, up ); #if 1 for (i = i - 1; i > 1 && distBackFromHead < distToTarget; i--) { Vector p0 = m_vecHeadGoal - m_vecHeadDir * distBackFromHead * 1.0; m_body[i].vecGoalPos = p0; if ((m_vecTarget - m_body[i].vecPos).Length() > distToTarget + distBackFromHead) { m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget); } else { m_body[i].vecGoalPos = EyePosition( ) - m_vecHeadDir * distBackFromHead; m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget); } distBackFromHead += m_body[i].flActualLength; } #endif } return; case TASK_HYDRA_PULLBACK: { if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } CBaseEntity *pEnemy = (CBaseEntity *)UTIL_GetLocalPlayer(); if (GetEnemy() != NULL) { pEnemy = GetEnemy(); } AimHeadInTravelDirection( 0.2 ); // float dist = (EyePosition() - m_vecHeadGoal).Length(); if (m_flCurrentLength < m_idealLength + m_idealSegmentLength) { 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); } }
//----------------------------------------------------------------------------- // 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_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; } }
//========================================================= // start task //========================================================= void CNPC_Houndeye::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HOUND_GET_PATH_TO_CIRCLE: { if (GetEnemy() == NULL) { TaskFail(FAIL_NO_ENEMY); } else { Vector vTargetPos = GetEnemyLKP(); vTargetPos.z = GetFloorZ(vTargetPos); if (GetNavigator()->SetRadialGoal(vTargetPos, random->RandomInt(50,500), 90, 175, m_bLoopClockwise)) { TaskComplete(); return; } TaskFail(FAIL_NO_ROUTE); } break; } case TASK_HOUND_REVERSE_STRAFE_DIR: { // Try the other direction m_bLoopClockwise = (m_bLoopClockwise) ? false : true; TaskComplete(); break; } // Override to set appropriate distances case TASK_GET_PATH_TO_ENEMY_LOS: { float flMaxRange = HOUNDEYE_MAX_ATTACK_RADIUS * 0.9; float flMinRange = HOUNDEYE_MIN_ATTACK_RADIUS; Vector posLos; bool foundLos = false; if (GetEnemy() != NULL) { foundLos = GetTacticalServices()->FindLos(GetEnemyLKP(),GetEnemy()->EyePosition(), flMinRange, flMaxRange, 0.0, &posLos); } else { TaskFail(FAIL_NO_TARGET); return; } if (foundLos) { GetNavigator()->SetGoal( AI_NavGoal_t( posLos, ACT_RUN, AIN_HULL_TOLERANCE ) ); } else { TaskFail(FAIL_NO_SHOOT); } break; } case TASK_HOUND_FALL_ASLEEP: { m_fAsleep = true; // signal that hound is lying down (must stand again before doing anything else!) TaskComplete( true ); break; } case TASK_HOUND_WAKE_UP: { m_fAsleep = false; // signal that hound is standing again TaskComplete( true ); break; } case TASK_HOUND_OPEN_EYE: { m_fDontBlink = false; // turn blinking back on and that code will automatically open the eye TaskComplete( true ); break; } case TASK_HOUND_CLOSE_EYE: { //<<TEMP>> pev->skin = 0; m_fDontBlink = true; // tell blink code to leave the eye alone. break; } case TASK_HOUND_THREAT_DISPLAY: { SetIdealActivity( ACT_IDLE_ANGRY ); break; } case TASK_HOUND_HOP_BACK: { SetIdealActivity( ACT_LEAP ); break; } case TASK_RANGE_ATTACK1: { SetIdealActivity( ACT_RANGE_ATTACK1 ); break; } default: { BaseClass::StartTask(pTask); break; } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_FearBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FEAR_WAIT_FOR_SAFETY: if( HasCondition(COND_SEE_ENEMY) ) { m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME; } else { if( gpGlobals->curtime > m_flTimeToSafety ) { TaskComplete(); } } break; case TASK_FEAR_GET_PATH_TO_SAFETY_HINT: { switch( GetOuter()->GetTaskInterrupt() ) { case 0:// Find the hint node { ReleaseAllHints(); CAI_Hint *pHint = FindFearWithdrawalDest(); if( pHint == NULL ) { TaskFail("Fear: Couldn't find hint node\n"); m_flDeferUntil = gpGlobals->curtime + 3.0f;// Don't bang the hell out of this behavior. If we don't find a node, take a short break and run regular AI. } else { m_hMovingToHint.Set( pHint ); GetOuter()->TaskInterrupt(); } } break; case 1:// Do the pathfinding. { Assert( m_hMovingToHint != NULL ); AI_NavGoal_t goal(m_hMovingToHint->GetAbsOrigin()); goal.pTarget = NULL; if( GetNavigator()->SetGoal( goal ) == false ) { m_hMovingToHint.Set( NULL ); // Do whatever we'd want to do if we can't find a path /* Msg("Can't path to the Fear Hint!\n"); 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; } */ } else { GetNavigator()->SetArrivalDirection( m_hMovingToHint->GetAbsAngles() ); } } break; } } break; default: BaseClass::RunTask( pTask ); break; } }
void CBigMomma::StartTask( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_FIND_NODE: { CBaseEntity *pTarget = m_hTargetEnt; if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) { if ( pTarget ) pev->netname = m_hTargetEnt->pev->target; } NodeStart( pev->netname ); TaskComplete(); ALERT( at_aiconsole, "BM: Found node %s\n", STRING(pev->netname) ); } break; case TASK_NODE_DELAY: m_nodeTime = gpGlobals->time + pTask->flData; TaskComplete(); ALERT( at_aiconsole, "BM: FAIL! Delay %.2f\n", pTask->flData ); break; case TASK_PROCESS_NODE: ALERT( at_aiconsole, "BM: Reached node %s\n", STRING(pev->netname) ); NodeReach(); TaskComplete(); break; case TASK_PLAY_NODE_PRESEQUENCE: case TASK_PLAY_NODE_SEQUENCE: { int sequence; if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) sequence = GetNodeSequence(); else sequence = GetNodePresequence(); ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING(sequence) ); if ( sequence ) { sequence = LookupSequence( STRING( sequence ) ); if ( sequence != -1 ) { pev->sequence = sequence; pev->frame = 0; ResetSequenceInfo( ); ALERT( at_aiconsole, "BM: Sequence %s\n", STRING(GetNodeSequence()) ); return; } } TaskComplete(); } break; case TASK_NODE_YAW: pev->ideal_yaw = GetNodeYaw(); TaskComplete(); break; case TASK_WAIT_NODE: m_flWait = gpGlobals->time + GetNodeDelay(); if ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING(pev->netname) ); else ALERT( at_aiconsole, "BM: Wait at node %s for %.2f\n", STRING(pev->netname), GetNodeDelay() ); break; case TASK_MOVE_TO_NODE_RANGE: { CBaseEntity *pTarget = m_hTargetEnt; if ( !pTarget ) TaskFail(); else { if ( (pTarget->pev->origin - pev->origin).Length() < GetNodeRange() ) TaskComplete(); else { Activity act = ACT_WALK; if ( pTarget->pev->spawnflags & SF_INFOBM_RUN ) act = ACT_RUN; m_vecMoveGoal = pTarget->pev->origin; if ( !MoveToTarget( act, 2 ) ) { TaskFail(); } } } } ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING(pev->netname) ); break; case TASK_MELEE_ATTACK1: // Play an attack sound here EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), 1.0, ATTN_NORM, 0, PITCH_NORM ); CBaseMonster::StartTask( pTask ); break; default: CBaseMonster::StartTask( pTask ); break; } }
void CController :: Move ( float flInterval ) { float flWaypointDist; float flCheckDist; float flDist;// how far the lookahead check got before hitting an object. float flMoveDist; Vector vecDir; Vector vecApex; CBaseEntity *pTargetEnt; // Don't move if no valid route if ( FRouteClear() ) { ALERT( at_aiconsole, "Tried to move with no route!\n" ); TaskFail(); return; } if ( m_flMoveWaitFinished > gpGlobals->time ) return; // Debug, test movement code #if 0 // if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) { if ( m_movementGoal == MOVEGOAL_ENEMY ) RouteSimplify( m_hEnemy ); else RouteSimplify( m_hTargetEnt ); FRefreshRoute(); return; } #else // Debug, draw the route // DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); #endif // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer // to that entity for the CheckLocalMove and Triangulate functions. pTargetEnt = NULL; if (m_flGroundSpeed == 0) { m_flGroundSpeed = 100; // TaskFail( ); // return; } flMoveDist = m_flGroundSpeed * flInterval; do { // local move to waypoint. vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); // MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); // ChangeYaw ( pev->yaw_speed ); // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint if ( flWaypointDist < DIST_TO_CHECK ) { flCheckDist = flWaypointDist; } else { flCheckDist = DIST_TO_CHECK; } if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) { // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) pTargetEnt = m_hEnemy; } else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) { pTargetEnt = m_hTargetEnt; } // !!!BUGBUG - CheckDist should be derived from ground speed. // If this fails, it should be because of some dynamic entity blocking this guy. // We've already checked this path, so we should wait and time out if the entity doesn't move flDist = 0; if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) { CBaseEntity *pBlocker; // Can't move, stop Stop(); // Blocking entity is in global trace_ent pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); if (pBlocker) { DispatchBlocked( edict(), pBlocker->edict() ); } if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) { // Can we still move toward our target? if ( flDist < m_flGroundSpeed ) { // Wait for a second m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; // ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); return; } } else { // try to triangulate around whatever is in the way. if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) { InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); RouteSimplify( pTargetEnt ); } else { ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); Stop(); if ( m_moveWaitTime > 0 ) { FRefreshRoute(); m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; } else { TaskFail(); ALERT( at_aiconsole, "Failed to move!\n" ); //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); } return; } } } // UNDONE: this is a hack to quit moving farther than it has looked ahead. if (flCheckDist < flMoveDist) { MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); // ALERT( at_console, "%.02f\n", flInterval ); AdvanceRoute( flWaypointDist ); flMoveDist -= flCheckDist; } else { MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); if ( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) { AdvanceRoute( flWaypointDist ); } flMoveDist = 0; } if ( MovementIsComplete() ) { Stop(); RouteClear(); } } while (flMoveDist > 0 && flCheckDist > 0); // cut corner? if (flWaypointDist < 128) { if ( m_movementGoal == MOVEGOAL_ENEMY ) RouteSimplify( m_hEnemy ); else RouteSimplify( m_hTargetEnt ); FRefreshRoute(); if (m_flGroundSpeed > 100) m_flGroundSpeed -= 40; } else { if (m_flGroundSpeed < 400) m_flGroundSpeed += 10; } }