void CAI_Motor::MoveFacing( const AILocalMoveGoal_t &move ) { if ( GetOuter()->OverrideMoveFacing( move, GetMoveInterval() ) ) return; // required movement direction float flMoveYaw = UTIL_VecToYaw( move.dir ); int nSequence = GetSequence(); float fSequenceMoveYaw = GetSequenceMoveYaw( nSequence ); if ( fSequenceMoveYaw == NOMOTION ) { fSequenceMoveYaw = 0; } if (!HasPoseParameter( nSequence, "move_yaw" )) { SetIdealYawAndUpdate( UTIL_AngleMod( flMoveYaw - fSequenceMoveYaw ) ); } else { // FIXME: move this up to navigator so that path goals can ignore these overrides. Vector dir; float flInfluence = GetFacingDirection( dir ); dir = move.facing * (1 - flInfluence) + dir * flInfluence; VectorNormalize( dir ); // ideal facing direction float idealYaw = UTIL_AngleMod( UTIL_VecToYaw( dir ) ); // FIXME: facing has important max velocity issues SetIdealYawAndUpdate( idealYaw ); // find movement direction to compensate for not being turned far enough float flDiff = UTIL_AngleDiff( flMoveYaw, GetLocalAngles().y ); SetPoseParameter( "move_yaw", flDiff ); /* if ((GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)) { Msg( "move %.1f : diff %.1f : ideal %.1f\n", flMoveYaw, flDiff, m_IdealYaw ); } */ } }
//----------------------------------------------------------------------------- // Make sure our target is still valid, and if so, fire at it //----------------------------------------------------------------------------- void CObjectSentrygun::Attack() { StudioFrameAdvance( ); if ( !FindTarget() ) { m_iState.Set( SENTRY_STATE_SEARCHING ); m_hEnemy = NULL; return; } // Track enemy Vector vecMid = EyePosition(); Vector vecMidEnemy = m_hEnemy->WorldSpaceCenter(); Vector vecDirToEnemy = vecMidEnemy - vecMid; QAngle angToTarget; VectorAngles( vecDirToEnemy, angToTarget ); angToTarget.y = UTIL_AngleMod( angToTarget.y ); if (angToTarget.x < -180) angToTarget.x += 360; if (angToTarget.x > 180) angToTarget.x -= 360; // now all numbers should be in [1...360] // pin to turret limitations to [-50...50] if (angToTarget.x > 50) angToTarget.x = 50; else if (angToTarget.x < -50) angToTarget.x = -50; m_vecGoalAngles.y = angToTarget.y; m_vecGoalAngles.x = angToTarget.x; MoveTurret(); // Fire on the target if it's within 10 units of being aimed right at it if ( m_flNextAttack <= gpGlobals->curtime && (m_vecGoalAngles - m_vecCurAngles).Length() <= 10 ) { Fire(); if ( m_iUpgradeLevel == 1 ) { // Level 1 sentries fire slower m_flNextAttack = gpGlobals->curtime + 0.2; } else { m_flNextAttack = gpGlobals->curtime + 0.1; } } else { // SetSentryAnim( TFTURRET_ANIM_SPIN ); } }
//----------------------------------------------------------------------------- // Called when a rotation happens //----------------------------------------------------------------------------- void C_ObjectSentrygun::RecomputeOrientation( ) { m_iRightBound = UTIL_AngleMod( m_vecCurAngles.y - 50); m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y + 50); if ( m_iRightBound > m_iLeftBound ) { m_iRightBound = m_iLeftBound; m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y - 50); } // Start it rotating m_vecGoalAngles.y = m_iRightBound;; m_vecGoalAngles.x = m_vecCurAngles.x = 0; m_fBoneXRotator = 0.0f; m_fBoneYRotator = 0.0f; m_bTurningRight = true; }
bool CNPC_Infected::OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ) { // required movement direction float flMoveYaw = UTIL_VecToYaw( move.dir ); // FIXME: move this up to navigator so that path goals can ignore these overrides. Vector dir; float flInfluence = GetFacingDirection( dir ); dir = move.facing * (1 - flInfluence) + dir * flInfluence; VectorNormalize( dir ); // ideal facing direction float idealYaw = UTIL_AngleMod( UTIL_VecToYaw( dir ) ); // FIXME: facing has important max velocity issues GetMotor()->SetIdealYawAndUpdate( idealYaw ); // find movement direction to compensate for not being turned far enough float flDiff = UTIL_AngleDiff( flMoveYaw, GetLocalAngles().y ); // Setup the 9-way blend parameters based on our speed and direction. Vector2D vCurMovePose( 0, 0 ); vCurMovePose.x = cos( DEG2RAD( flDiff ) ) * 1.0f; //flPlaybackRate; vCurMovePose.y = -sin( DEG2RAD( flDiff ) ) * 1.0f; //flPlaybackRate; SetPoseParameter( gm_nMoveXPoseParam, vCurMovePose.x ); SetPoseParameter( gm_nMoveYPoseParam, vCurMovePose.y ); // ==== Update Lean pose parameters if ( gm_nLeanYawPoseParam >= 0 ) { float targetLean = GetPoseParameter( gm_nMoveYPoseParam ) * 30.0f; float curLean = GetPoseParameter( gm_nLeanYawPoseParam ); if( curLean < targetLean ) curLean += MIN(fabs(targetLean-curLean), GetAnimTimeInterval()*12.0f); //was 15.0f else curLean -= MIN(fabs(targetLean-curLean), GetAnimTimeInterval()*12.0f); //was 15.0f SetPoseParameter( gm_nLeanYawPoseParam, curLean ); } if( gm_nLeanPitchPoseParam >= 0 ) { float targetLean = GetPoseParameter( gm_nMoveXPoseParam ) * -20.0f; //was -30.0f float curLean = GetPoseParameter( gm_nLeanPitchPoseParam ); if( curLean < targetLean ) curLean += MIN(fabs(targetLean-curLean), GetAnimTimeInterval()*10.0f); //was 15.0f else curLean -= MIN(fabs(targetLean-curLean), GetAnimTimeInterval()*10.0f); //was 15.0f SetPoseParameter( gm_nLeanPitchPoseParam, curLean ); } return true; }
Vector CTank :: TourelleAngle ( void ) { UTIL_MakeVectors(pev->angles ); Vector angle = UTIL_VecToAngles( gpGlobals->v_forward ); angle.x += pev->v_angle.x; angle.y += pev->v_angle.y; angle.y = UTIL_AngleMod( angle.y ); angle.x = -angle.x; return angle; }
//========================================================= // DeltaIdealYaw - returns the difference ( in degrees ) between // npc's current yaw and ideal_yaw // // Positive result is left turn, negative is right turn //========================================================= float CAI_Motor::DeltaIdealYaw ( void ) { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( GetLocalAngles().y ); if ( flCurrentYaw == GetIdealYaw() ) { return 0; } return UTIL_AngleDiff( GetIdealYaw(), flCurrentYaw ); }
void CBaseTurret::Deploy(void) { pev->nextthink = gpGlobals->time + 0.1; StudioFrameAdvance( ); if (pev->sequence != TURRET_ANIM_DEPLOY) { m_iOn = 1; SetTurretAnim(TURRET_ANIM_DEPLOY); EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_deploy.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); SUB_UseTargets( this, USE_ON, 0 ); } if (m_fSequenceFinished) { pev->maxs.z = m_iDeployHeight; pev->mins.z = -m_iDeployHeight; UTIL_SetSize(pev, pev->mins, pev->maxs); m_vecCurAngles.x = 0; if (m_iOrientation == 1) { m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); } else { m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); } SetTurretAnim(TURRET_ANIM_SPIN); pev->framerate = 0; SetThink(&CBaseTurret::SearchThink); } m_flLastSight = gpGlobals->time + m_flMaxWait; }
void CAI_Motor::UpdateYaw( int yawSpeed ) { float ideal, current, newYaw; if ( yawSpeed = -1 ) yawSpeed = GetYawSpeed(); // NOTE: GetIdealYaw() will never exactly be reached because UTIL_AngleMod // also truncates the angle to 16 bits of resolution. So lets truncate it here. current = UTIL_AngleMod( GetLocalAngles().y ); ideal = UTIL_AngleMod( GetIdealYaw() ); newYaw = AI_ClampYaw( (float)yawSpeed * 10.0, current, ideal, gpGlobals->curtime - GetLastThink() ); if (newYaw != current) { QAngle angles = GetLocalAngles(); angles.y = newYaw; SetLocalAngles( angles ); // ENTITY MUST BE RELINKED to recompute absangles engine->RelinkEntity( GetEdict(), false ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Vector CBaseTFPlayer::GenerateFireVector( Vector *viewVector ) { // Calculate the weapon spread from the player's accuracy float flAcc = (GetAccuracy() * 0.5) / ACCURACY_DISTANCE; float flAccuracyAngle = RAD2DEG( atan( flAcc ) ); // If the user passed in a viewVector, use it, otherwise use player's v_angle Vector angShootAngles = viewVector ? *viewVector : pl->v_angle; if ( flAccuracyAngle ) { 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); angShootAngles.x = UTIL_AngleMod( angShootAngles.x + (x * flAccuracyAngle) ); angShootAngles.y = UTIL_AngleMod( angShootAngles.y + (y * flAccuracyAngle) ); } Vector forward; AngleVectors( angShootAngles, &forward ); return forward; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_RappelBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_MOVE_AWAY_PATH: GetOuter()->GetMotor()->SetIdealYaw( UTIL_AngleMod( GetOuter()->GetLocalAngles().y - 180.0f ) ); BaseClass::StartTask( pTask ); break; case TASK_RANGE_ATTACK1: BaseClass::StartTask( pTask ); break; case TASK_RAPPEL: { CreateZipline(); SetDescentSpeed(); } break; case TASK_HIT_GROUND: m_bOnGround = true; if( GetOuter()->GetGroundEntity() != NULL && GetOuter()->GetGroundEntity()->IsNPC() && GetOuter()->GetGroundEntity()->m_iClassname == GetOuter()->m_iClassname ) { // Although I tried to get NPC's out from under me, I landed on one. Kill it, so long as it's the same type of character as me. variant_t val; val.SetFloat( 0 ); g_EventQueue.AddEvent( GetOuter()->GetGroundEntity(), "sethealth", val, 0, GetOuter(), GetOuter() ); } TaskComplete(); break; default: BaseClass::StartTask( pTask ); break; } }
AIMoveResult_t CAI_LocalNavigator::MoveCalc( AILocalMoveGoal_t *pMoveGoal, bool bPreviouslyValidated ) { bool bOnlyCurThink = ( bPreviouslyValidated && !HaveObstacles() ); AIMoveResult_t result = MoveCalcRaw( pMoveGoal, bOnlyCurThink ); if ( pMoveGoal->curExpectedDist > pMoveGoal->maxDist ) pMoveGoal->curExpectedDist = pMoveGoal->maxDist; // If success, try to dampen really fast turning movement if ( result == AIMR_OK) { float interval = GetOuter()->GetMotor()->GetMoveInterval(); float currentYaw = UTIL_AngleMod( GetLocalAngles().y ); float goalYaw; float deltaYaw; float speed; float clampedYaw; // Clamp yaw goalYaw = UTIL_VecToYaw( pMoveGoal->facing ); deltaYaw = fabs( UTIL_AngleDiff( goalYaw, currentYaw ) ); if ( deltaYaw > 15 ) { speed = deltaYaw * 4.0; // i.e., any maneuver takes a quarter a second clampedYaw = AI_ClampYaw( speed, currentYaw, goalYaw, interval ); if ( clampedYaw != goalYaw ) { pMoveGoal->facing = UTIL_YawToVector( clampedYaw ); } } } return result; }
//------------------------------------------------------------------------------ // 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; } }
//----------------------------------------------------------------------------- // Purpose: Handle movement of the turret //----------------------------------------------------------------------------- bool C_ObjectSentrygun::MoveTurret(void) { bool bMoved = 0; float turnrate = (float)(m_iBaseTurnRate) * 10.0f; turnrate *= gpGlobals->frametime; // any x movement? if ( m_vecCurAngles.x != m_vecGoalAngles.x ) { float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; m_vecCurAngles.x += 0.1 * (turnrate * 5) * flDir; // if we started below the goal, and now we're past, peg to goal if (flDir == 1) { if (m_vecCurAngles.x > m_vecGoalAngles.x) m_vecCurAngles.x = m_vecGoalAngles.x; } else { if (m_vecCurAngles.x < m_vecGoalAngles.x) m_vecCurAngles.x = m_vecGoalAngles.x; } m_fBoneYRotator = m_vecCurAngles.x; bMoved = 1; } if ( m_vecCurAngles.y != m_vecGoalAngles.y ) { float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); bool bReversed = false; if (flDist > 180) { flDist = 360 - flDist; flDir = -flDir; bReversed = true; } if (m_hEnemy == NULL ) { if (flDist > 30) { if (m_fTurnRate < turnrate * 20) { m_fTurnRate += turnrate; } } else { // Slow down if ( m_fTurnRate > (turnrate * 5) ) m_fTurnRate -= turnrate; } } else { // When tracking enemies, move faster and don't slow if (flDist > 30) { if (m_fTurnRate < turnrate * 30) { m_fTurnRate += turnrate * 3; } } } m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; // if we passed over the goal, peg right to it now if (flDir == -1) { if ( (bReversed == false && m_vecGoalAngles.y > m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y < m_vecCurAngles.y) ) m_vecCurAngles.y = m_vecGoalAngles.y; } else { if ( (bReversed == false && m_vecGoalAngles.y < m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y > m_vecCurAngles.y) ) m_vecCurAngles.y = m_vecGoalAngles.y; } if (m_vecCurAngles.y < 0) m_vecCurAngles.y += 360; else if (m_vecCurAngles.y >= 360) m_vecCurAngles.y -= 360; if (flDist < (0.05 * turnrate)) m_vecCurAngles.y = m_vecGoalAngles.y; m_fBoneXRotator = m_vecCurAngles.y - UTIL_AngleMod( GetAbsAngles().y ); bMoved = 1; } if ( !bMoved || !m_fTurnRate ) m_fTurnRate = turnrate; if ( bMoved ) { NetworkStateChanged(); } return bMoved; }
void C_ObjectSentrygun::ClientThink( void ) { // Turtling sentryguns don't think if ( IsTurtled() ) return; if ( IsPlacing() || IsBuilding() ) return; if ( m_hEnemy != NULL ) { // Figure out where we're firing at Vector vecMid = EyePosition(); Vector vecFireTarget = m_hEnemy->WorldSpaceCenter(); // + vecMid; // BodyTarget( vecMid ); Vector vecDirToEnemy = vecFireTarget - vecMid; QAngle angToTarget; VectorAngles(vecDirToEnemy, angToTarget); angToTarget.y = UTIL_AngleMod( angToTarget.y ); if (angToTarget.x < -180) angToTarget.x += 360; if (angToTarget.x > 180) angToTarget.x -= 360; // now all numbers should be in [1...360] // pin to turret limitations to [-50...50] if (angToTarget.x > 50) angToTarget.x = 50; else if (angToTarget.x < -50) angToTarget.x = -50; m_vecGoalAngles.y = angToTarget.y; m_vecGoalAngles.x = angToTarget.x; MoveTurret(); return; } // Rotate if ( !MoveTurret() ) { // Play a sound occasionally if ( random->RandomFloat(0, 1) < 0.02 ) { EmitSound( "ObjectSentrygun.Idle" ); } // Switch rotation direction if (m_bTurningRight) { m_bTurningRight = false; m_vecGoalAngles.y = m_iLeftBound; } else { m_bTurningRight = true; m_vecGoalAngles.y = m_iRightBound; } // Randomly look up and down a bit if ( random->RandomFloat(0, 1) < 0.3 ) { m_vecGoalAngles.x = (int)random->RandomFloat(-10,10); } } }
//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. //========================================================= void CBaseMonster :: StartTask ( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_TURN_RIGHT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); SetTurnActivity(); break; } case TASK_TURN_LEFT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); SetTurnActivity(); break; } case TASK_REMEMBER: { Remember ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FORGET: { Forget ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FIND_HINTNODE: { m_iHintNode = FindHintNode(); if ( m_iHintNode != NO_NODE ) { TaskComplete(); } else { TaskFail(); } break; } case TASK_STORE_LASTPOSITION: { m_vecLastPosition = pev->origin; TaskComplete(); break; } case TASK_CLEAR_LASTPOSITION: { m_vecLastPosition = g_vecZero; TaskComplete(); break; } case TASK_CLEAR_HINTNODE: { m_iHintNode = NO_NODE; TaskComplete(); break; } case TASK_STOP_MOVING: { if ( m_IdealActivity == m_movementActivity ) { m_IdealActivity = GetStoppedActivity(); } RouteClear(); TaskComplete(); break; } case TASK_PLAY_SEQUENCE_FACE_ENEMY: case TASK_PLAY_SEQUENCE_FACE_TARGET: case TASK_PLAY_SEQUENCE: { m_IdealActivity = ( Activity )( int )pTask->flData; break; } case TASK_PLAY_ACTIVE_IDLE: { // monsters verify that they have a sequence for the node's activity BEFORE // moving towards the node, so it's ok to just set the activity without checking here. m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; break; } case TASK_SET_SCHEDULE: { Schedule_t *pNewSchedule; pNewSchedule = GetScheduleOfType( (int)pTask->flData ); if ( pNewSchedule ) { ChangeSchedule( pNewSchedule ); } else { TaskFail(); } break; } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ENEMY: { entvars_t *pevCover; if ( m_hEnemy == NULL ) { // Find cover from self if no enemy available pevCover = pev; // TaskFail(); // return; } else pevCover = m_hEnemy->pev; if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ORIGIN: { if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no cover! TaskFail(); } } break; case TASK_FIND_COVER_FROM_BEST_SOUND: { CSound *pBestSound; pBestSound = PBestSound(); ASSERT( pBestSound != NULL ); /* if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } */ if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. or no sound in list TaskFail(); } break; } case TASK_FACE_HINTNODE: { pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; SetTurnActivity(); break; } case TASK_FACE_LASTPOSITION: MakeIdealYaw ( m_vecLastPosition ); SetTurnActivity(); break; case TASK_FACE_TARGET: if ( m_hTargetEnt != NULL ) { MakeIdealYaw ( m_hTargetEnt->pev->origin ); SetTurnActivity(); } else TaskFail(); break; case TASK_FACE_ENEMY: { MakeIdealYaw ( m_vecEnemyLKP ); SetTurnActivity(); break; } case TASK_FACE_IDEAL: { SetTurnActivity(); break; } case TASK_FACE_ROUTE: { if (FRouteClear()) { ALERT(at_aiconsole, "No route to face!\n"); TaskFail(); } else { MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); SetTurnActivity(); } break; } case TASK_WAIT_PVS: case TASK_WAIT_INDEFINITE: { // don't do anything. break; } case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + pTask->flData; break; } case TASK_WAIT_RANDOM: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); break; } case TASK_MOVE_TO_TARGET_RANGE: { if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { m_vecMoveGoal = m_hTargetEnt->pev->origin; if ( !MoveToTarget( ACT_WALK, 2 ) ) TaskFail(); } break; } case TASK_RUN_TO_SCRIPT: case TASK_WALK_TO_SCRIPT: { Activity newActivity; if ( !m_pGoalEnt || (m_pGoalEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { if ( pTask->iTask == TASK_WALK_TO_SCRIPT ) newActivity = ACT_WALK; else newActivity = ACT_RUN; // This monster can't do this! if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) TaskComplete(); else { if ( m_pGoalEnt != NULL ) { Vector vecDest; vecDest = m_pGoalEnt->pev->origin; if ( !MoveToLocation( newActivity, 2, vecDest ) ) { TaskFail(); ALERT( at_aiconsole, "%s Failed to reach script!!!\n", STRING(pev->classname) ); RouteClear(); } } else { TaskFail(); ALERT( at_aiconsole, "%s: MoveTarget is missing!?!\n", STRING(pev->classname) ); RouteClear(); } } } TaskComplete(); break; } case TASK_CLEAR_MOVE_WAIT: { m_flMoveWaitFinished = gpGlobals->time; TaskComplete(); break; } case TASK_MELEE_ATTACK1_NOTURN: case TASK_MELEE_ATTACK1: { m_IdealActivity = ACT_MELEE_ATTACK1; break; } case TASK_MELEE_ATTACK2_NOTURN: case TASK_MELEE_ATTACK2: { m_IdealActivity = ACT_MELEE_ATTACK2; break; } case TASK_RANGE_ATTACK1_NOTURN: case TASK_RANGE_ATTACK1: { m_IdealActivity = ACT_RANGE_ATTACK1; break; } case TASK_RANGE_ATTACK2_NOTURN: case TASK_RANGE_ATTACK2: { m_IdealActivity = ACT_RANGE_ATTACK2; break; } case TASK_RELOAD_NOTURN: case TASK_RELOAD: { m_IdealActivity = ACT_RELOAD; break; } case TASK_SPECIAL_ATTACK1: { m_IdealActivity = ACT_SPECIAL_ATTACK1; break; } case TASK_SPECIAL_ATTACK2: { m_IdealActivity = ACT_SPECIAL_ATTACK2; break; } case TASK_SET_ACTIVITY: { m_IdealActivity = (Activity)(int)pTask->flData; TaskComplete(); break; } case TASK_GET_PATH_TO_ENEMY_LKP: { if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) { 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 ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) { TaskComplete(); } else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY_CORPSE: { UTIL_MakeVectors( pev->angles ); if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else { ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); TaskFail(); } } break; case TASK_GET_PATH_TO_SPOT: { CBaseEntity *pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_TARGET: { RouteClear(); if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_SCRIPT: { RouteClear(); if ( m_pCine != NULL && MoveToLocation( m_movementActivity, 1, m_pCine->pev->origin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_HINTNODE:// for active idles! { if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_LASTPOSITION: { m_vecMoveGoal = m_vecLastPosition; if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSOUND: { CSound *pSound; pSound = PBestSound(); if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSCENT: { CSound *pScent; pScent = PBestScent(); if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); TaskFail(); } break; } case TASK_RUN_PATH: { // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_RUN; } else { m_movementActivity = ACT_WALK; } TaskComplete(); break; } case TASK_WALK_PATH: { if ( pev->movetype == MOVETYPE_FLY ) { m_movementActivity = ACT_FLY; } if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_WALK; } else { m_movementActivity = ACT_RUN; } TaskComplete(); break; } case TASK_STRAFE_PATH: { Vector2D vec2DirToPoint; Vector2D vec2RightSide; // to start strafing, we have to first figure out if the target is on the left side or right side UTIL_MakeVectors ( pev->angles ); vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) { // strafe right m_movementActivity = ACT_STRAFE_RIGHT; } else { // strafe left m_movementActivity = ACT_STRAFE_LEFT; } TaskComplete(); break; } case TASK_WAIT_FOR_MOVEMENT: { if (FRouteClear()) { TaskComplete(); } break; } case TASK_EAT: { Eat( pTask->flData ); TaskComplete(); break; } case TASK_SMALL_FLINCH: { m_IdealActivity = GetSmallFlinchActivity(); break; } case TASK_DIE: { RouteClear(); m_IdealActivity = GetDeathActivity(); pev->deadflag = DEAD_DYING; break; } case TASK_SOUND_WAKE: { AlertSound(); TaskComplete(); break; } case TASK_SOUND_DIE: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_IDLE: { IdleSound(); TaskComplete(); break; } case TASK_SOUND_PAIN: { PainSound(); TaskComplete(); break; } case TASK_SOUND_DEATH: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_ANGRY: { // sounds are complete as soon as we get here, cause we've already played them. ALERT ( at_aiconsole, "SOUND\n" ); TaskComplete(); break; } case TASK_WAIT_FOR_SCRIPT: { if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) { TaskComplete(); //LRC - start playing immediately } else if (!m_pCine->IsAction() && m_pCine->m_iszIdle) { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) { pev->framerate = 0; } } else m_IdealActivity = ACT_IDLE; break; } case TASK_PLAY_SCRIPT: { if (m_pCine->IsAction()) { //ALERT(at_console,"PlayScript: setting idealactivity %d\n",m_pCine->m_fAction); switch(m_pCine->m_fAction) { case 0: m_IdealActivity = ACT_RANGE_ATTACK1; break; case 1: m_IdealActivity = ACT_RANGE_ATTACK2; break; case 2: m_IdealActivity = ACT_MELEE_ATTACK1; break; case 3: m_IdealActivity = ACT_MELEE_ATTACK2; break; case 4: m_IdealActivity = ACT_SPECIAL_ATTACK1; break; case 5: m_IdealActivity = ACT_SPECIAL_ATTACK2; break; case 6: m_IdealActivity = ACT_RELOAD; break; case 7: m_IdealActivity = ACT_HOP; break; } pev->framerate = 1.0; // shouldn't be needed, but just in case pev->movetype = MOVETYPE_FLY; ClearBits(pev->flags, FL_ONGROUND); } else { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); if ( m_fSequenceFinished ) ClearSchedule(); pev->framerate = 1.0; //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); } m_scriptState = SCRIPT_PLAYING; break; } case TASK_ENABLE_SCRIPT: { m_pCine->DelayStart( 0 ); TaskComplete(); break; } //LRC case TASK_END_SCRIPT: { m_pCine->SequenceDone( this ); TaskComplete(); break; } case TASK_PLANT_ON_SCRIPT: { if ( m_pCine != NULL ) { // Plant on script // LRC - if it's a teleport script, do the turn too if (m_pCine->m_fMoveTo == 4 || m_pCine->m_fMoveTo == 6) { if (m_pCine->m_fTurnType == 0) //LRC pev->angles.y = m_hTargetEnt->pev->angles.y; else if (m_pCine->m_fTurnType == 1) pev->angles.y = UTIL_VecToYaw(m_hTargetEnt->pev->origin - pev->origin); pev->ideal_yaw = pev->angles.y; pev->avelocity = Vector( 0, 0, 0 ); pev->velocity = Vector( 0, 0, 0 ); pev->effects |= EF_NOINTERP; } if (m_pCine->m_fMoveTo != 6) pev->origin = m_pGoalEnt->pev->origin; } TaskComplete(); break; } case TASK_FACE_SCRIPT: { if ( m_pCine != NULL && m_pCine->m_fMoveTo != 0) // movetype "no move" makes us ignore turntype { switch (m_pCine->m_fTurnType) { case 0: pev->ideal_yaw = UTIL_AngleMod( m_pCine->pev->angles.y ); break; case 1: // yes, this is inconsistent- turn to face uses the "target" and turn to angle uses the "cine". if (m_hTargetEnt) MakeIdealYaw ( m_hTargetEnt->pev->origin ); else MakeIdealYaw ( m_pCine->pev->origin ); break; // default: don't turn } } TaskComplete(); m_IdealActivity = ACT_IDLE; RouteClear(); break; } case TASK_SUGGEST_STATE: { m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; TaskComplete(); break; } case TASK_SET_FAIL_SCHEDULE: m_failSchedule = (int)pTask->flData; TaskComplete(); break; case TASK_CLEAR_FAIL_SCHEDULE: m_failSchedule = SCHED_NONE; TaskComplete(); break; default: { ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); break; } } }
void CLeech::SwimThink( void ) { TraceResult tr; float flLeftSide; float flRightSide; float targetSpeed; float targetYaw = 0; CBaseEntity *pTarget; if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); pev->velocity = g_vecZero; return; } else pev->nextthink = gpGlobals->time + 0.1; targetSpeed = LEECH_SWIM_SPEED; if ( m_waterTime < gpGlobals->time ) RecalculateWaterlevel(); if ( m_stateTime < gpGlobals->time ) SwitchLeechState(); ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: pTarget = m_hEnemy; if ( !pTarget ) SwitchLeechState(); else { // Chase the enemy's eyes m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5; // Clip to viable water area if ( m_height < m_bottom ) m_height = m_bottom; else if ( m_height > m_top ) m_height = m_top; Vector location = pTarget->pev->origin - pev->origin; location.z += (pTarget->pev->view_ofs.z); if ( location.Length() < 40 ) SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); // Turn towards target ent targetYaw = UTIL_VecToYaw( location ); targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( pev->angles.y ) ); if ( targetYaw < (-LEECH_TURN_RATE*0.75) ) targetYaw = (-LEECH_TURN_RATE*0.75); else if ( targetYaw > (LEECH_TURN_RATE*0.75) ) targetYaw = (LEECH_TURN_RATE*0.75); else targetSpeed *= 2; } break; default: if ( m_zTime < gpGlobals->time ) { float newHeight = RANDOM_FLOAT( m_bottom, m_top ); m_height = 0.5 * m_height + 0.5 * newHeight; m_zTime = gpGlobals->time + RANDOM_FLOAT( 1, 4 ); } if ( RANDOM_LONG( 0, 100 ) < 10 ) targetYaw = RANDOM_LONG( -30, 30 ); pTarget = NULL; // oldorigin test if ( (pev->origin - pev->oldorigin).Length() < 1 ) { // If leech didn't move, there must be something blocking it, so try to turn m_sideTime = 0; } break; } m_obstacle = ObstacleDistance( pTarget ); pev->oldorigin = pev->origin; if ( m_obstacle < 0.1 ) m_obstacle = 0.1; // is the way ahead clear? if ( m_obstacle == 1.0 ) { // if the leech is turning, stop the trend. if ( m_flTurning != 0 ) { m_flTurning = 0; } m_fPathBlocked = FALSE; pev->speed = UTIL_Approach( targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME ); pev->velocity = gpGlobals->v_forward * pev->speed; } else { m_obstacle = 1.0 / m_obstacle; // IF we get this far in the function, the leader's path is blocked! m_fPathBlocked = TRUE; if ( m_flTurning == 0 )// something in the way and leech is not already turning to avoid { Vector vecTest; // measure clearance on left and right to pick the best dir to turn vecTest = pev->origin + (gpGlobals->v_right * LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); flRightSide = tr.flFraction; vecTest = pev->origin + (gpGlobals->v_right * -LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); flLeftSide = tr.flFraction; // turn left, right or random depending on clearance ratio float delta = (flRightSide - flLeftSide); if ( delta > 0.1 || (delta > -0.1 && RANDOM_LONG(0,100)<50) ) m_flTurning = -LEECH_TURN_RATE; else m_flTurning = LEECH_TURN_RATE; } pev->speed = UTIL_Approach( -(LEECH_SWIM_SPEED*0.5), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle ); pev->velocity = gpGlobals->v_forward * pev->speed; } pev->ideal_yaw = m_flTurning + targetYaw; UpdateMotion(); }
//------------------------------------------------------------------------------ // Purpose: routine called to start when a task initially starts // Input : pTask - the task structure //------------------------------------------------------------------------------ void CAI_ASW_ShieldBehavior::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_SHIELD_RAISE: GetOuter()->SetIdealActivity( ACT_SHIELD_UP ); break; case TASK_SHIELD_LOWER: GetOuter()->SetIdealActivity( ACT_SHIELD_DOWN ); break; case TASK_SHIELD_MAINTAIN: m_TurningGesture = ACT_INVALID; if ( m_flEndFrozenTime < gpGlobals->curtime ) { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { float flIdealYaw = UTIL_VecToYaw( pTarget->GetAbsOrigin() - GetLocalOrigin() ); float flYawDiff = UTIL_AngleMod( GetLocalAngles().y - flIdealYaw ); if ( flYawDiff > 180.0f && flYawDiff < 330.0f ) { m_TurningGesture = ACT_GESTURE_TURN_LEFT45; GetOuter()->RestartGesture( m_TurningGesture ); GetOuter()->SetIdealActivity( ACT_SHIELD_UP_IDLE ); } else if ( flYawDiff <= 180.0f && flYawDiff > 30.0f ) { m_TurningGesture = ACT_GESTURE_TURN_RIGHT45; GetOuter()->RestartGesture( m_TurningGesture ); GetOuter()->SetIdealActivity( ACT_SHIELD_UP_IDLE ); } } } if ( m_TurningGesture == ACT_INVALID ) { if ( m_flEndFrozenTime > gpGlobals->curtime ) { if ( m_bBeganFrozen == false ) { m_bBeganFrozen = true; GetOuter()->SetIdealActivity( ACT_CROUCHING_SHIELD_UP ); } else { GetOuter()->SetIdealActivity( ACT_CROUCHING_SHIELD_UP_IDLE ); } } else { GetOuter()->SetIdealActivity( ACT_SHIELD_UP_IDLE ); } } break; case TASK_SHIELD_MAINTAIN_FLIP: { bool bNeedFlip = false; if ( HaveSequenceForActivity( ACT_SPINAROUND ) == true ) { CBaseEntity *pTarget = GetEnemy(); if ( pTarget ) { float flIdealYaw = UTIL_VecToYaw( pTarget->GetAbsOrigin() - GetLocalOrigin() ); float flYawDiff = UTIL_AngleMod( GetLocalAngles().y - flIdealYaw ); if ( fabs( flYawDiff - 180.0f ) <= 40.0f ) { bNeedFlip = true; } } } if ( bNeedFlip == false ) { TaskComplete(); } else { GetOuter()->SetIdealActivity( ACT_SPINAROUND ); } } 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; } }
//----------------------------------------------------------------------------- // 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 ); } } }
void CSentry :: SentryDeath( void ) { BOOL iActive = FALSE; StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; if (pev->deadflag != DEAD_DEAD) { pev->deadflag = DEAD_DEAD; float flRndSound = RANDOM_FLOAT ( 0 , 1 ); if ( flRndSound <= 0.33 ) EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); else if ( flRndSound <= 0.66 ) EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); else EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); SetTurretAnim(TURRET_ANIM_DIE); pev->solid = SOLID_NOT; pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); EyeOn( ); } EyeOff( ); Vector vecSrc, vecAng; GetAttachment( 1, vecSrc, vecAng ); if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) { // lots of smoke MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_SMOKE ); WRITE_COORD( vecSrc.x + RANDOM_FLOAT( -16, 16 ) ); WRITE_COORD( vecSrc.y + RANDOM_FLOAT( -16, 16 ) ); WRITE_COORD( vecSrc.z - 32 ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 15 ); // scale * 10 WRITE_BYTE( 8 ); // framerate MESSAGE_END(); } if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) { UTIL_Sparks( vecSrc ); } if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) { pev->framerate = 0; SetThink( NULL ); } }
//----------------------------------------------------------------------------- // 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; } } }
//----------------------------------------------------------------------------- // 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 ); }
void CNPC_CombineDropship::SpawnTroops( void ) { int i; // char szAttachmentName[ 32 ]; Vector vecLocation; QAngle vecAngles; QAngle vecSpawnAngles; // memset( szAttachmentName, 0, 32 ); vecSpawnAngles = GetLocalAngles(); vecSpawnAngles.y = UTIL_AngleMod( vecSpawnAngles.y - 180 ); vecSpawnAngles.x = 0; vecSpawnAngles.z = 0; for( i = 1 ; i <= m_soldiersToDrop ; i++ ) { // Q_snprintf( szAttachmentName,sizeof(szAttachmentName), "spot%d", i ); // GetAttachment( szAttachmentName, vecLocation, vecAngles ); vecLocation = GetAbsOrigin(); vecAngles = GetAbsAngles(); // troops spawn behind vehicle at all times Vector shipDir, shipLeft; AngleVectors( vecAngles, &shipDir, &shipLeft, NULL ); vecLocation -= shipDir * 250; // set spawn position for spawning in formation switch( i ) { case 1: vecLocation -= shipLeft * DROPSHIP_TROOP_GRID; break; case 3: vecLocation += shipLeft * DROPSHIP_TROOP_GRID; break; case 4: vecLocation -= shipDir * DROPSHIP_TROOP_GRID - shipLeft * DROPSHIP_TROOP_GRID; break; case 5: vecLocation -= shipDir * DROPSHIP_TROOP_GRID; break; case 6: vecLocation -= shipDir * DROPSHIP_TROOP_GRID + shipLeft * DROPSHIP_TROOP_GRID; } // spawn based upon template CAI_BaseNPC *pEnt = NULL; CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_sNPCTemplateData), NULL ); if ( pEntity != NULL ) { pEnt = (CAI_BaseNPC *)pEntity; } else { Warning("Dropship could not create template NPC\n" ); return; } pEnt->SetLocalOrigin( vecLocation ); pEnt->SetLocalAngles( vecSpawnAngles ); DispatchSpawn( pEnt ); pEnt->m_NPCState = NPC_STATE_IDLE; pEnt->SetOwnerEntity( this ); pEnt->Activate(); } }