void CNPC_Cremator::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CREMATOR_RANGE_ATTACK1: { SetActivity( ACT_RANGE_ATTACK1 ); Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTargetAndUpdate( flEnemyLKP ); if( m_iAmmo < 1 && IsActivityFinished() ) { SetCondition( COND_CREMATOR_OUT_OF_AMMO ); DevMsg( "NO PRIMARY AMMO\n" ); StopParticleEffects(this); StopSound( "Weapon_Immolator.Single" ); EmitSound( "Weapon_Immolator.Stop" ); TaskComplete(); SetNextThink( gpGlobals->curtime + 0.1f ); } // THIS fixes the combat issue with the Cremator continuing to fire at a target that moved out of his reach if( GetEnemyLKP().DistTo( GetAbsOrigin()) > CREMATOR_MAX_RANGE ) { // Cremator stops firing and attempts to close the distance. SetActivity( ACT_CREMATOR_DISARM ); TaskComplete(); Msg( "Enemy is too far\n" ); SetNextThink( gpGlobals->curtime + 0.1f ); return; } /* // This is bugged and shouldn't be used. Necessary checks are made below, in OnChangeActivity( ). if( IsActivityMovementPhased( ACT_WALK ) || IsActivityMovementPhased( ACT_RUN ) ) { TaskFail( NULL ); SetActivity( ACT_CREMATOR_DISARM ); DevMsg( "ACT_CREMATOR_DISARM\n" ); return; } */ break; } default: BaseClass::RunTask( pTask ); break; } }
// make the harvester look at his enemy bool CASW_Harvester::OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ) { Vector vecFacePosition = vec3_origin; CBaseEntity *pFaceTarget = NULL; bool bFaceTarget = false; if ( GetEnemy() && GetNavigator()->GetMovementActivity() == ACT_RUN ) { Vector vecEnemyLKP = GetEnemyLKP(); // Only start facing when we're close enough if ( ( UTIL_DistApprox( vecEnemyLKP, GetAbsOrigin() ) < 1500 ) ) { vecFacePosition = vecEnemyLKP; pFaceTarget = GetEnemy(); bFaceTarget = true; } } // Face if ( bFaceTarget ) { AddFacingTarget( pFaceTarget, vecFacePosition, 1.0, 0.2 ); } return BaseClass::OverrideMoveFacing( move, flInterval ); }
void CNPC_Infected::RunAttackTask( int task ) { AutoMovement( ); Vector vecEnemyLKP = GetEnemyLKP(); // If our enemy was killed, but I'm not done animating, the last known position comes // back as the origin and makes the me face the world origin if my attack schedule // doesn't break when my enemy dies. (sjb) if( vecEnemyLKP != vec3_origin ) { if ( ( task == TASK_RANGE_ATTACK1 || task == TASK_RELOAD ) && ( CapabilitiesGet() & bits_CAP_AIM_GUN ) && FInAimCone( vecEnemyLKP ) ) { // Arms will aim, so leave body yaw as is GetMotor()->SetIdealYawAndUpdate( GetMotor()->GetIdealYaw(), AI_KEEP_YAW_SPEED ); } else { GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP, AI_KEEP_YAW_SPEED ); } } CAnimationLayer *pPlayer = GetAnimOverlay( m_iAttackLayer ); if ( pPlayer->m_bSequenceFinished ) { if ( task == TASK_RELOAD && GetShotRegulator() ) { GetShotRegulator()->Reset( false ); } TaskComplete(); } }
//----------------------------------------------------------------------------- // Purpose: // Input : flInterval - //----------------------------------------------------------------------------- void CNPC_WpnScanner::MoveToAttack(float flInterval) { if (GetEnemy() == NULL) return; if ( flInterval <= 0 ) return; Vector vTargetPos = GetEnemyLKP(); Vector idealPos = IdealGoalForMovement( vTargetPos, GetAbsOrigin(), GetGoalDistance(), 128 ); NDebugOverlay::Box( idealPos, -Vector(4,4,4), Vector(4,4,4), 0,255,0,8, 0.1 ); MoveToTarget( flInterval, idealPos ); //FIXME: Re-implement? /* // --------------------------------------------------------- // Add evasion if I have taken damage recently // --------------------------------------------------------- if ((m_flLastDamageTime + SCANNER_EVADE_TIME) > gpGlobals->curtime) { vFlyDirection = vFlyDirection + VelocityToEvade(GetEnemyCombatCharacterPointer()); } */ }
//========================================================= // RunTask //========================================================= void CNPC_HAssassin::RunTask ( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_ASSASSIN_FALL_TO_GROUND: GetMotor()->SetIdealYawAndUpdate( GetEnemyLKP() ); if ( IsSequenceFinished() ) { if ( GetAbsVelocity().z > 0) { SetActivity( ACT_ASSASSIN_FLY_UP ); } else if ( HasCondition ( COND_SEE_ENEMY )) { SetActivity( ACT_ASSASSIN_FLY_ATTACK ); SetCycle( 0 ); } else { SetActivity( ACT_ASSASSIN_FLY_DOWN ); SetCycle( 0 ); } ResetSequenceInfo( ); } if ( GetFlags() & FL_ONGROUND) { TaskComplete( ); } else if( gpGlobals->curtime > m_flWaitFinished || GetAbsVelocity().z == 0.0 ) { // I've waited two seconds and haven't hit the ground. Try to force it. trace_t trace; UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 1 ), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &trace ); if( trace.DidHitWorld() ) { SetGroundEntity( trace.m_pEnt ); } else { // Try again in a couple of seconds. m_flWaitFinished = gpGlobals->curtime + 2.0f; } } break; default: BaseClass::RunTask ( pTask ); break; } }
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); } }
//----------------------------------------------------------------------------- // TASK_RANGE_ATTACK1 / TASK_RANGE_ATTACK2 / etc. //----------------------------------------------------------------------------- void CAI_BaseHumanoid::RunTaskRangeAttack1( const Task_t *pTask ) { if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 ) { BaseClass::RunTask( pTask ); return; } AutoMovement( ); Vector vecEnemyLKP = GetEnemyLKP(); // If our enemy was killed, but I'm not done animating, the last known position comes // back as the origin and makes the me face the world origin if my attack schedule // doesn't break when my enemy dies. (sjb) if( vecEnemyLKP != vec3_origin ) { if ( ( pTask->iTask == TASK_RANGE_ATTACK1 || pTask->iTask == TASK_RELOAD ) && ( CapabilitiesGet() & bits_CAP_AIM_GUN ) && FInAimCone( vecEnemyLKP ) ) { // Arms will aim, so leave body yaw as is GetMotor()->SetIdealYawAndUpdate( GetMotor()->GetIdealYaw(), AI_KEEP_YAW_SPEED ); } else { GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP, AI_KEEP_YAW_SPEED ); } } if ( IsActivityFinished() ) { if ( !GetEnemy() || !GetEnemy()->IsAlive() ) { TaskComplete(); return; } if ( !GetShotRegulator()->IsInRestInterval() ) { if ( GetShotRegulator()->ShouldShoot() ) { OnRangeAttack1(); ResetIdealActivity( ACT_RANGE_ATTACK1 ); } return; } TaskComplete(); } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_RappelBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_RAPPEL: { // If we don't do this, the beam won't show up sometimes. Ideally, all beams would update their // bboxes correctly, but we're close to shipping and we can't change that now. if ( m_hLine ) { m_hLine->RelinkBeam(); } if( GetEnemy() ) { // Face the enemy if there's one. Vector vecEnemyLKP = GetEnemyLKP(); GetOuter()->GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP ); } SetDescentSpeed(); if( GetOuter()->GetFlags() & FL_ONGROUND ) { CBaseEntity *pGroundEnt = GetOuter()->GetGroundEntity(); if( pGroundEnt && pGroundEnt->IsPlayer() ) { // try to shove the player in the opposite direction as they are facing (so they'll see me) Vector vecForward; pGroundEnt->GetVectors( &vecForward, NULL, NULL ); pGroundEnt->SetAbsVelocity( vecForward * -500 ); break; } GetOuter()->m_OnRappelTouchdown.FireOutput( GetOuter(), GetOuter(), 0 ); GetOuter()->RemoveFlag( FL_FLY ); CutZipline(); TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
void CZombie::GatherConditions( void ) { BaseClass::GatherConditions(); static int conditionsToClear[] = { COND_BLOCKED_BY_DOOR, COND_DOOR_OPENED, COND_ZOMBIE_CHARGE_TARGET_MOVED, }; ClearConditions( conditionsToClear, ARRAYSIZE( conditionsToClear ) ); if ( m_hBlockingDoor == NULL || ( m_hBlockingDoor->m_toggle_state == TS_AT_TOP || m_hBlockingDoor->m_toggle_state == TS_GOING_UP ) ) { ClearCondition( COND_BLOCKED_BY_DOOR ); if ( m_hBlockingDoor != NULL ) { SetCondition( COND_DOOR_OPENED ); m_hBlockingDoor = NULL; } } else SetCondition( COND_BLOCKED_BY_DOOR ); if ( ConditionInterruptsCurSchedule( COND_ZOMBIE_CHARGE_TARGET_MOVED ) ) { if ( GetNavigator()->IsGoalActive() ) { const float CHARGE_RESET_TOLERANCE = 60.0; if ( !GetEnemy() || ( m_vPositionCharged - GetEnemyLKP() ).Length() > CHARGE_RESET_TOLERANCE ) { SetCondition( COND_ZOMBIE_CHARGE_TARGET_MOVED ); } } } }
//========================================================= // RunTask //========================================================= void CNPC_Houndeye::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HOUND_THREAT_DISPLAY: { GetMotor()->SetIdealYawToTargetAndUpdate( GetEnemyLKP(), AI_KEEP_YAW_SPEED ); if ( IsActivityFinished() ) { TaskComplete(); } break; } case TASK_HOUND_CLOSE_EYE: { /*//<<TEMP>> if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) { pev->skin++; } */ break; } case TASK_HOUND_HOP_BACK: { if ( IsActivityFinished() ) { TaskComplete(); } break; } default: { BaseClass::RunTask(pTask); break; } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_RappelBehavior::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_RAPPEL: { // If we don't do this, the beam won't show up sometimes. Ideally, all beams would update their // bboxes correctly, but we're close to shipping and we can't change that now. if ( m_hLine ) { m_hLine->RelinkBeam(); } if( GetEnemy() ) { // Face the enemy if there's one. Vector vecEnemyLKP = GetEnemyLKP(); GetOuter()->GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP ); } SetDescentSpeed(); if( GetOuter()->GetFlags() & FL_ONGROUND ) { GetOuter()->m_OnRappelTouchdown.FireOutput( GetOuter(), GetOuter(), 0 ); GetOuter()->RemoveFlag( FL_FLY ); CutZipline(); TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CNPC_Cremator::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CREMATOR_IDLE: { SetActivity( ACT_IDLE ); if( IsActivityFinished() ) { TaskComplete(); } break; } case TASK_CREMATOR_RANGE_ATTACK1: { Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); break; } default: BaseClass::StartTask( pTask ); break; } }
//========================================================= // Hornet is flying, gently tracking target //========================================================= void CNPC_Hornet::TrackTarget ( void ) { Vector vecFlightDir; Vector vecDirToEnemy; float flDelta; Vector vecEnemyLKP; StudioFrameAdvance( ); if (gpGlobals->curtime > m_flStopAttack) { SetTouch( NULL ); SetThink( SUB_Remove ); SetNextThink( gpGlobals->curtime + 0.1f ); return; } // UNDONE: The player pointer should come back after returning from another level if ( GetEnemy() == NULL ) {// enemy is dead. GetSenses()->Look( 512 ); SetEnemy( BestEnemy() ); } if ( GetEnemy() != NULL && FVisible( GetEnemy() )) { vecEnemyLKP = GetEnemy()->BodyTarget( GetAbsOrigin() ); } else { vecEnemyLKP = GetEnemyLKP() + GetAbsVelocity() * m_flFlySpeed * 0.1; } vecDirToEnemy = vecEnemyLKP - GetAbsOrigin(); VectorNormalize( vecDirToEnemy ); if ( GetAbsVelocity().Length() < 0.1 ) vecFlightDir = vecDirToEnemy; else { vecFlightDir = GetAbsVelocity(); VectorNormalize( vecFlightDir ); } SetAbsVelocity( vecFlightDir + vecDirToEnemy ); // measure how far the turn is, the wider the turn, the slow we'll go this time. flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); if ( flDelta < 0.5 ) {// hafta turn wide again. play sound CPASAttenuationFilter filter( this ); switch (random->RandomInt(0,2)) { case 0: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 1: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 2: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; } } if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. flDelta = 0.25; } Vector vecVel = GetAbsVelocity(); VectorNormalize( vecVel ); if ( GetOwnerEntity() && (GetOwnerEntity()->GetFlags() & FL_NPC) ) { // random pattern only applies to hornets fired by monsters, not players. vecVel.x += random->RandomFloat ( -0.10, 0.10 );// scramble the flight dir a bit. vecVel.y += random->RandomFloat ( -0.10, 0.10 ); vecVel.z += random->RandomFloat ( -0.10, 0.10 ); } SetAbsVelocity( vecVel ); switch ( m_iHornetType ) { case HORNET_TYPE_RED: SetAbsVelocity( GetAbsVelocity() * ( m_flFlySpeed * flDelta ) );// scale the dir by the ( speed * width of turn ) SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.3 ) ); break; case HORNET_TYPE_ORANGE: SetAbsVelocity( GetAbsVelocity() * m_flFlySpeed );// do not have to slow down to turn. SetNextThink( gpGlobals->curtime + 0.1f );// fixed think time break; } QAngle angNewAngles; VectorAngles( GetAbsVelocity(), angNewAngles ); SetAbsAngles( angNewAngles ); SetSolid( SOLID_BBOX ); // if hornet is close to the enemy, jet in a straight line for a half second. // (only in the single player game) if ( GetEnemy() != NULL && !g_pGameRules->IsMultiplayer() ) { if ( flDelta >= 0.4 && ( GetAbsOrigin() - vecEnemyLKP ).Length() <= 300 ) { CPVSFilter filter( GetAbsOrigin() ); te->Sprite( filter, 0.0, &GetAbsOrigin(), // pos iHornetPuff, // model 0.2, //size 128 // brightness ); CPASAttenuationFilter filter2( this ); switch ( random->RandomInt(0,2)) { case 0: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 1: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 2: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; } SetAbsVelocity( GetAbsVelocity() * 2 ); SetNextThink( gpGlobals->curtime + 1.0f ); // don't attack again m_flStopAttack = gpGlobals->curtime; } } }
//========================================================= // CheckRangeAttack1 //========================================================= bool CNPC_HL1Barney::CheckRangeAttack1 ( float flDot, float flDist ) { if ( gpGlobals->curtime > m_flCheckAttackTime ) { trace_t tr; Vector shootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 ); CBaseEntity *pEnemy = GetEnemy(); Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->GetAbsOrigin()) + GetEnemyLKP() ); UTIL_TraceLine ( shootOrigin, shootTarget, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); m_flCheckAttackTime = gpGlobals->curtime + 1; if ( tr.fraction == 1.0 || ( tr.m_pEnt != NULL && tr.m_pEnt == pEnemy) ) m_fLastAttackCheck = TRUE; else m_fLastAttackCheck = FALSE; m_flCheckAttackTime = gpGlobals->curtime + 1.5; } return m_fLastAttackCheck; }
// Здесь происходит назначение различных ф-ций во время анимации. Аним-ивенты назначаются в .qc. void CNPC_Cremator::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case CREMATOR_AE_FLLEFT: // левый шаг { LeftFootHit( pEvent->eventtime ); } break; case CREMATOR_AE_FLRIGHT: // правый шаг { RightFootHit( pEvent->eventtime ); } break; case CREMATOR_AE_IMMO_START: // начало анимации атаки { //CBaseEntity *pEntity; DispatchSpray( this ); DevMsg( "%i ammo left\n", m_iAmmo ); Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTargetAndUpdate( flEnemyLKP ); } break; case CREMATOR_AE_IMMO_PARTICLE: // Маркер для запуска системы частиц огнемета { DispatchParticleEffect( "flamethrower", PATTACH_POINT_FOLLOW, this, "muzzle" ); // Если нужно заменить зеленый огонь оранжевым, замени "flamethrower" на "flamethrower_orange". EmitSound( "Weapon_Immolator.Single" ); } break; case CREMATOR_AE_IMMO_PARTICLEOFF: // Маркер для отключения системы частиц огнемета { StopParticleEffects( this ); StopSound( "Weapon_Immolator.Single" ); EmitSound( "Weapon_Immolator.Stop" ); } break; case CREMATOR_AE_RELOAD: { ClearCondition( COND_CREMATOR_OUT_OF_AMMO ); ClearCondition( COND_NO_PRIMARY_AMMO ); m_iAmmo += 54; // Put your own int here. This defines for how long a cremator would be able to fire at an enemy. DevMsg( "AE_RELOAD\n" ); } break; case CREMATOR_AE_THROWGRENADE: // Маркер для броска гранаты { DevMsg( "Throwing incendiary grenade!\n" ); ThrowIncendiaryGrenade(); if( g_pGameRules->IsSkillLevel(SKILL_EASY) ) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 15.0f, 30.0f ); } else if( g_pGameRules->IsSkillLevel(SKILL_HARD) ) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 5.0f, 10.0f ); } else if (g_pGameRules->IsSkillLevel(SKILL_VERYHARD)) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat(3.0f, 5.0f); } else if (g_pGameRules->IsSkillLevel(SKILL_NIGHTMARE)) { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat(1.0f, 3.0f); } else { m_flNextRangeAttack2Time = gpGlobals->curtime + random->RandomFloat( 10.0f, 20.0f ); } } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//========================================================= // start task //========================================================= void CNPC_Stalker::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_STALKER_SCREAM: { if( gpGlobals->curtime > m_flNextScreamTime ) { EmitSound( "NPC_Stalker.Scream" ); m_flNextScreamTime = gpGlobals->curtime + random->RandomFloat( 10.0, 15.0 ); } TaskComplete(); } case TASK_ANNOUNCE_ATTACK: { // If enemy isn't facing me and I haven't attacked in a while // annouce my attack before I start wailing away CBaseCombatCharacter *pBCC = GetEnemyCombatCharacterPointer(); if (pBCC && (!pBCC->FInViewCone ( this )) && (gpGlobals->curtime - m_flLastAttackTime > 1.0) ) { m_flLastAttackTime = gpGlobals->curtime; // Always play this sound EmitSound( "NPC_Stalker.Scream" ); m_flNextScrambleSoundTime = gpGlobals->curtime + 2; m_flNextBreatheSoundTime = gpGlobals->curtime + 2; // Wait two seconds SetWait( 2.0 ); SetActivity(ACT_IDLE); } break; } case TASK_STALKER_ZIGZAG: break; case TASK_RANGE_ATTACK1: { CBaseEntity *pEnemy = GetEnemy(); if (pEnemy) { m_vLaserTargetPos = GetEnemyLKP() + pEnemy->GetViewOffset(); // Never hit target on first try Vector missPos = m_vLaserTargetPos; if( pEnemy->Classify() == CLASS_BULLSEYE && hl2_episodic.GetBool() ) { missPos.x += 60 + 120*random->RandomInt(-1,1); missPos.y += 60 + 120*random->RandomInt(-1,1); } else { missPos.x += 80*random->RandomInt(-1,1); missPos.y += 80*random->RandomInt(-1,1); } // ---------------------------------------------------------------------- // If target is facing me and not running towards me shoot below his feet // so he can see the laser coming // ---------------------------------------------------------------------- CBaseCombatCharacter *pBCC = ToBaseCombatCharacter(pEnemy); if (pBCC) { Vector targetToMe = (pBCC->GetAbsOrigin() - GetAbsOrigin()); Vector vBCCFacing = pBCC->BodyDirection2D( ); if ((DotProduct(vBCCFacing,targetToMe) < 0) && (pBCC->GetSmoothedVelocity().Length() < 50)) { missPos.z -= 150; } // -------------------------------------------------------- // If facing away or running towards laser, // shoot above target's head // -------------------------------------------------------- else { missPos.z += 60; } } m_vLaserDir = missPos - LaserStartPosition(GetAbsOrigin()); VectorNormalize(m_vLaserDir); } else { TaskFail(FAIL_NO_ENEMY); return; } StartAttackBeam(); SetActivity(ACT_RANGE_ATTACK1); break; } case TASK_GET_PATH_TO_ENEMY_LOS: { if ( GetEnemy() != NULL ) { BaseClass:: StartTask( pTask ); return; } Vector posLos; if (GetTacticalServices()->FindLos(m_vLaserCurPos, m_vLaserCurPos, MIN_STALKER_FIRE_RANGE, MAX_STALKER_FIRE_RANGE, 1.0, &posLos)) { AI_NavGoal_t goal( posLos, ACT_RUN, AIN_HULL_TOLERANCE ); GetNavigator()->SetGoal( goal ); } else { TaskFail(FAIL_NO_SHOOT); } break; } case TASK_FACE_ENEMY: { if ( GetEnemy() != NULL ) { BaseClass:: StartTask( pTask ); return; } GetMotor()->SetIdealYawToTarget( m_vLaserCurPos ); 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; } } }
void CNPC_AlienGrunt::StartTask ( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_AGRUNT_RANGE_ATTACK1_NOTURN: { SetLastAttackTime( gpGlobals->curtime ); ResetIdealActivity( ACT_RANGE_ATTACK1 ); } break; case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: { Vector forward; AngleVectors( GetAbsAngles(), &forward ); Vector flEnemyLKP = GetEnemyLKP(); GetNavigator()->SetGoal( flEnemyLKP - forward * 64, AIN_CLEAR_TARGET); if ( GetNavigator()->SetGoal( flEnemyLKP - forward * 64, AIN_CLEAR_TARGET) ) { TaskComplete(); } else { Msg ( "AGruntGetPathToEnemyCorpse failed!!\n" ); TaskFail( FAIL_NO_ROUTE ); } } break; case TASK_AGRUNT_SETUP_HIDE_ATTACK: // alien grunt shoots hornets back out into the open from a concealed location. // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. CHL1BaseNPC *pEnemyMonsterPtr; pEnemyMonsterPtr = (CHL1BaseNPC *)GetEnemy()->MyNPCPointer(); if ( pEnemyMonsterPtr ) { Vector vecCenter, vForward, vRight, vecEnemyLKP; QAngle angTmp; trace_t tr; BOOL fSkip; fSkip = FALSE; vecCenter = WorldSpaceCenter(); vecEnemyLKP = GetEnemyLKP(); VectorAngles( vecEnemyLKP - GetAbsOrigin(), angTmp ); SetAbsAngles( angTmp ); AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL ); UTIL_TraceLine( WorldSpaceCenter() + vForward * 128, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() + vRight * 128 ); fSkip = TRUE; TaskComplete(); } if ( !fSkip ) { UTIL_TraceLine( WorldSpaceCenter() - vForward * 128, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() - vRight * 128 ); fSkip = TRUE; TaskComplete(); } } if ( !fSkip ) { UTIL_TraceLine( WorldSpaceCenter() + vForward * 256, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() + vRight * 256 ); fSkip = TRUE; TaskComplete(); } } if ( !fSkip ) { UTIL_TraceLine( WorldSpaceCenter() - vForward * 256, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() - vRight * 256 ); fSkip = TRUE; TaskComplete(); } } if ( !fSkip ) { TaskFail( FAIL_NO_COVER ); } } else { Msg ( "AGRunt - no enemy monster ptr!!!\n" ); TaskFail( FAIL_NO_ENEMY ); } break; default: BaseClass::StartTask ( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CFastZombie::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FASTZOMBIE_VERIFY_ATTACK: // Simply ensure that the zombie still has a valid melee attack if( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) { TaskComplete(); } else { TaskFail(""); } break; case TASK_FASTZOMBIE_JUMP_BACK: { SetActivity( ACT_IDLE ); RemoveFlag( FL_ONGROUND ); BeginAttackJump(); Vector forward; AngleVectors( GetLocalAngles(), &forward ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); ApplyAbsVelocityImpulse( forward * -200 + Vector( 0, 0, 200 ) ); } break; case TASK_FASTZOMBIE_UNSTICK_JUMP: { RemoveFlag( FL_ONGROUND ); // Call begin attack jump. A little bit later if we fail to pathfind, we check // this value to see if we just jumped. If so, we assume we've jumped // to someplace that's not pathing friendly, and so must jump again to get out. BeginAttackJump(); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); CBaseEntity *pEnemy = GetEnemy(); Vector vecJumpDir; if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN ) { // Jump off the pipe backwards! Vector forward; GetVectors( &forward, NULL, NULL ); ApplyAbsVelocityImpulse( forward * -200 ); } else if( pEnemy ) { vecJumpDir = pEnemy->GetLocalOrigin() - GetLocalOrigin(); VectorNormalize( vecJumpDir ); vecJumpDir.z = 0; ApplyAbsVelocityImpulse( vecJumpDir * 300 + Vector( 0, 0, 200 ) ); } else { Msg("UNHANDLED CASE! Stuck Fast Zombie with no enemy!\n"); } } break; case TASK_WAIT_FOR_MOVEMENT: // If we're waiting for movement, that means that pathfinding succeeded, and // we're about to be moving. So we aren't stuck. So clear this flag. m_fJustJumped = false; BaseClass::StartTask( pTask ); break; case TASK_FACE_ENEMY: { // We don't use the base class implementation of this, because GetTurnActivity // stomps our landing scrabble animations (sjb) Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); } break; case TASK_FASTZOMBIE_LAND_RECOVER: { // Set the ideal yaw Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); // figure out which way to turn. float flDeltaYaw = GetMotor()->DeltaIdealYaw(); if( flDeltaYaw < 0 ) { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_RIGHT ); } else { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_LEFT ); } TaskComplete(); } break; case TASK_RANGE_ATTACK1: // Make melee attacks impossible until we land! m_flNextMeleeAttack = gpGlobals->curtime + 60; SetTouch( LeapAttackTouch ); break; case TASK_FASTZOMBIE_DO_ATTACK: SetActivity( (Activity)ACT_FASTZOMBIE_LEAP_SOAR ); break; default: BaseClass::StartTask( pTask ); break; } }