// drops us down from the specified position, to the floor bool CASW_Simple_Alien::ApplyGravity(Vector &vecSrc, float deltatime) { // decide if we're on the ground or not Ray_t ray; trace_t trace; CTraceFilterSimple traceFilter(this, GetCollisionGroup() ); ray.Init( vecSrc, vecSrc - Vector(0,0,2), GetHullMins(), GetHullMaxs() ); enginetrace->TraceRay( ray, MASK_NPCSOLID, &traceFilter, &trace ); m_bOnGround = (trace.fraction < 1.0f); // if we're on the ground, just drop us down as much as we can if (m_bOnGround) { Vector vecGravityTarget = vecSrc; vecGravityTarget.z -= sv_gravity.GetFloat() * deltatime; // do a trace to the floor Ray_t ray; trace_t trace; CTraceFilterSimple traceFilter(this, GetCollisionGroup() ); ray.Init( vecSrc, vecGravityTarget, GetHullMins(), GetHullMaxs() ); enginetrace->TraceRay( ray, MASK_NPCSOLID, &traceFilter, &trace ); if (trace.fraction > 0 && fabs(trace.endpos.z - vecSrc.z) > 1) // if we moved up/down { vecSrc = trace.endpos; return true; } m_fFallSpeed = 0; // clear fall speed if we can't fall any further return false; } // we're falling, so apply the fall speed and increase the fall speed over time m_fFallSpeed -= sv_gravity.GetFloat() * 1.5f * deltatime; Vector vecGravityTarget = vecSrc; vecGravityTarget.z += m_fFallSpeed * deltatime; // do a trace to the floor Ray_t ray2; trace_t trace2; CTraceFilterSimple traceFilter2(this, GetCollisionGroup() ); ray2.Init( vecSrc, vecGravityTarget, GetHullMins(), GetHullMaxs() ); enginetrace->TraceRay( ray2, MASK_NPCSOLID, &traceFilter2, &trace2 ); if (trace2.fraction > 0 && fabs(trace2.endpos.z - vecSrc.z) > 1) // if we moved up/down { vecSrc = trace2.endpos; return true; } m_fFallSpeed = 0; // clear fall speed if we can't fall any further return false; }
// make this alien jump off the head of the ent he's standing on bool CASW_Alien_Jumper::DoJumpOffHead() { //Too soon to try to jump if ( m_flJumpTime > gpGlobals->curtime ) return false; if (!(GetGroundEntity()) || GetNavType() == NAV_JUMP ) return false; // force this drone to have jumping capabilities m_bDisableJump = false; CapabilitiesAdd( bits_CAP_MOVE_JUMP ); //Vector vecDest = RandomVector(-1, 1); //vecDest.z = 0; //vecDest *= random->RandomFloat(30, 100); Vector vecDest; AngleVectors(GetAbsAngles(), &vecDest); vecDest *= 200.0f; vecDest += GetAbsOrigin(); // Try the jump AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 ); } m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 ); } //Save this jump in case the next time fails m_vecSavedJump = moveTrace.vJumpVelocity; m_vecLastJumpAttempt = vecDest; SetSchedule(SCHED_ASW_ALIEN_JUMP); m_bForcedStuckJump = true; return true; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTargetEnt - // vecDir - // flDistance - // flInterval - //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::MoveFlyExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flDistance, float flInterval ) { IchthyosaurMoveType_t eMoveType = ( GetNavigator()->CurWaypointIsGoal() ) ? ICH_MOVETYPE_ARRIVE : ICH_MOVETYPE_SEEK; m_flGroundSpeed = GetGroundSpeed(); Vector moveGoal = GetNavigator()->GetCurWaypointPos(); //See if we can move directly to our goal if ( ( GetEnemy() != NULL ) && ( GetNavigator()->GetGoalTarget() == (CBaseEntity *) GetEnemy() ) ) { trace_t tr; Vector goalPos = GetEnemy()->GetAbsOrigin() + ( GetEnemy()->GetSmoothedVelocity() * 0.5f ); AI_TraceHull( GetAbsOrigin(), goalPos, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, GetEnemy(), COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0f ) { moveGoal = tr.endpos; } } //Move DoMovement( flInterval, moveGoal, eMoveType ); //Save the info from that run m_vecLastMoveTarget = moveGoal; m_bHasMoveTarget = true; }
//----------------------------------------------------------------------------- // Purpose: // Input : flDot - // flDist - // Output : int CNPC_Assassin::RangeAttack1Conditions //----------------------------------------------------------------------------- int CNPC_Assassin::RangeAttack2Conditions ( float flDot, float flDist ) { if ( m_flNextLungeTime > gpGlobals->curtime ) return 0; float lungeRange = GetSequenceMoveDist( SelectWeightedSequence( (Activity) ACT_ASSASSIN_FLIP_FORWARD ) ); if ( flDist < lungeRange * 0.25f ) return COND_TOO_CLOSE_TO_ATTACK; if ( flDist > lungeRange * 1.5f ) return COND_TOO_FAR_TO_ATTACK; if ( flDot < 0.75f ) return COND_NOT_FACING_ATTACK; if ( GetEnemy() == NULL ) return 0; // Check for a clear path trace_t tr; UTIL_TraceHull( GetAbsOrigin(), GetEnemy()->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0f || tr.m_pEnt == GetEnemy() ) return COND_CAN_RANGE_ATTACK2; return 0; }
void CNPC_SO_BaseZombie::ForceMove( const Vector &targetPos, const Vector &traceDir, bool bRun ) { // Make sure our zombie gets the message (sometimes it is stubborn) // This bit should force our zombie to listen to us SetEnemy( NULL ); SetSchedule( SCHED_ZOMBIE_AMBUSH_MODE ); Vector chasePosition = targetPos; Vector vUpBit = chasePosition; vUpBit.z += 1; trace_t tr; AI_TraceHull( chasePosition, vUpBit, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); m_vecLastPosition = chasePosition; if ( m_hCine != NULL ) ExitScriptedSequence(); SetCondition( COND_RECEIVED_ORDERS ); if ( bRun ) SetSchedule( SCHED_FORCED_GO_RUN ); else SetSchedule( SCHED_FORCED_GO ); m_flMoveWaitFinished = gpGlobals->curtime; }
bool CASW_Alien_Jumper::DoJumpTo(Vector &vecDest) { //Too soon to try to jump if ( m_flJumpTime > gpGlobals->curtime ) return false; // only jump if you're on the ground if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP ) return false; // Don't jump if I'm not allowed if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false ) return false; // Try the jump AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 ); } m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 ); } //Save this jump in case the next time fails m_vecSavedJump = moveTrace.vJumpVelocity; m_vecLastJumpAttempt = vecDest; SetSchedule(SCHED_ASW_ALIEN_JUMP); m_bForcedStuckJump = true; //Msg("Drone saving jump vec %f %f %f\n", m_vecSavedJump.x, m_vecSavedJump.y, m_vecSavedJump.z); return true; }
int CASW_Parasite::RangeAttack1Conditions( float flDot, float flDist ) { if ( gpGlobals->curtime < m_flNextAttack ) return 0; if ( ( GetFlags() & FL_ONGROUND ) == false ) return 0; // This code stops lots of headcrabs swarming you and blocking you // whilst jumping up and down in your face over and over. It forces // them to back up a bit. If this causes problems, consider using it // for the fast headcrabs only, rather than just removing it.(sjb) if ( flDist < ASW_PARASITE_MIN_JUMP_DIST ) return COND_TOO_CLOSE_TO_ATTACK; if ( flDist > ASW_PARASITE_MAX_JUMP_DIST ) return COND_TOO_FAR_TO_ATTACK; // Make sure the way is clear! CBaseEntity *pEnemy = GetEnemy(); if( pEnemy ) { bool bEnemyIsBullseye = ( dynamic_cast<CNPC_Bullseye *>(pEnemy) != NULL ); trace_t tr; AI_TraceLine( EyePosition(), pEnemy->EyePosition(), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt != GetEnemy() ) { if ( !bEnemyIsBullseye || tr.m_pEnt != NULL ) return COND_NONE; } if( GetEnemy()->EyePosition().z - 36.0f > GetAbsOrigin().z ) { // Only run this test if trying to jump at a player who is higher up than me, else this // code will always prevent a headcrab from jumping down at an enemy, and sometimes prevent it // jumping just slightly up at an enemy. Vector vStartHullTrace = GetAbsOrigin(); vStartHullTrace.z += 1.0; Vector vEndHullTrace = GetEnemy()->EyePosition() - GetAbsOrigin(); vEndHullTrace.NormalizeInPlace(); vEndHullTrace *= 8.0; vEndHullTrace += GetAbsOrigin(); AI_TraceHull( vStartHullTrace, vEndHullTrace,GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, GetCollisionGroup(), &tr ); if ( tr.m_pEnt != NULL && tr.m_pEnt != GetEnemy() ) { return COND_TOO_CLOSE_TO_ATTACK; } } } return COND_CAN_RANGE_ATTACK1; }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CNPC_Ichthyosaur::Beached( void ) { trace_t tr; Vector testPos; testPos = GetAbsOrigin() - Vector( 0, 0, ICH_DEPTH_PREFERENCE ); AI_TraceHull( GetAbsOrigin(), testPos, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); return ( tr.fraction < 1.0f ); }
bool CASW_Simple_Alien::TryMove(const Vector &vecSrc, Vector &vecTarget, float deltatime, bool bStepMove) { // do a trace to the dest Ray_t ray; trace_t trace; CTraceFilterSimple traceFilter(this, GetCollisionGroup() ); ray.Init( vecSrc, vecTarget, GetHullMins(), GetHullMaxs() ); enginetrace->TraceRay( ray, MASK_NPCSOLID, &traceFilter, &trace ); if (trace.startsolid) { // doh, we're stuck in something! // todo: move us to a safe spot? wait for push out phys props? if (asw_debug_simple_alien.GetBool()) Msg("CASW_Simple_Alien stuck!\n"); m_MoveFailure.trace = trace; m_MoveFailure.vecStartPos = vecSrc; m_MoveFailure.vecTargetPos = vecTarget; return false; } if (trace.fraction < 0.1f) // barely/didn't move { // try and do a 'stepped up' move to the target if (!bStepMove) { Vector vecStepSrc = vecSrc; vecStepSrc.z += 24; Vector vecStepTarget = vecTarget; vecTarget.z += 24; if (TryMove(vecStepSrc, vecStepTarget, deltatime, true)) { vecTarget = vecStepTarget; return true; } } m_MoveFailure.trace = trace; m_MoveFailure.vecStartPos = vecSrc; m_MoveFailure.vecTargetPos = vecTarget; return false; } else if (trace.fraction < 1) // we hit something early, but we did move { // we hit something early m_MoveFailure.trace = trace; m_MoveFailure.vecStartPos = vecSrc; m_MoveFailure.vecTargetPos = vecTarget; vecTarget = trace.endpos; } return true; }
//----------------------------------------------------------------------------- // Purpose: Plays the engine sound. //----------------------------------------------------------------------------- void CNPC_Houndeye::NPCThink(void) { if (m_pEnergyWave) { if (gpGlobals->curtime > m_flEndEnergyWaveTime) { UTIL_Remove(m_pEnergyWave); m_pEnergyWave = NULL; } } // ----------------------------------------------------- // Update collision group // While I'm running I'm allowed to penetrate // other houndeyes // ----------------------------------------------------- Vector vVelocity; GetVelocity( &vVelocity, NULL ); if (vVelocity.Length() > 10) { SetCollisionGroup( HL2COLLISION_GROUP_HOUNDEYE ); } else { // Don't go solid if resting in another houndeye trace_t tr; AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,1), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if (!tr.startsolid) { SetCollisionGroup( COLLISION_GROUP_NONE ); } else { SetCollisionGroup( HL2COLLISION_GROUP_HOUNDEYE ); } } /* if (GetCollisionGroup() == HL2COLLISION_GROUP_HOUNDEYE) { NDebugOverlay::Box(GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 0); } else { NDebugOverlay::Box(GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 0); } */ BaseClass::NPCThink(); }
// Purpose: Returns true if a reasonable jumping distance bool CASW_Alien_Jumper::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const { const float MAX_JUMP_RISE = 512; //const float MIN_JUMP_RISE = 16; const float MAX_JUMP_DROP = 512; const float MAX_JUMP_DISTANCE = 1024; const float MIN_JUMP_DISTANCE = 128; // make sure we don't do really flat jumps //float fHeight = (apex.z - startPos.z); //Msg("checking legality of jump with height %f\n", fHeight); //if ((apex.z - startPos.z) < 10 || fHeight != 0) //return false; //Adrian: Don't try to jump if my destination is right next to me. if ( ( endPos - GetAbsOrigin()).Length() < MIN_JUMP_DISTANCE ) return false; if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) && asw_test_new_alien_jump.GetBool() == true ) { trace_t tr; AI_TraceHull( endPos, endPos, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt ) { CAI_BaseNPC *pBlocker = tr.m_pEnt->MyNPCPointer(); if ( pBlocker && pBlocker->Classify() == CLASS_ASW_DRONE ) { // HACKHACK - push other jumpers out of the way CASW_Alien_Jumper *pJumper = dynamic_cast< CASW_Alien_Jumper * > ( pBlocker ); if ( pJumper ) { if ( pJumper->AllowedToBePushed() == true ) { // NDebugOverlay::Line( GetAbsOrigin(), endPos, 255, 0, 0, 0, 2 ); // NDebugOverlay::Box( pAntlion->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 0, 255, 0, 2 ); pJumper->GetMotor()->SetIdealYawToTarget( endPos ); pJumper->SetSchedule( SCHED_MOVE_AWAY ); pJumper->m_flNextJumpPushTime = gpGlobals->curtime + 2.0f; } } } } } return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE ); }
//----------------------------------------------------------------------------- // Purpose: Looks ahead to see if we are going to hit something. If we are, a // recommended avoidance path is returned. // Input : vecMoveDir - // flSpeed - // vecDeflect - // Output : Returns true if we hit something and need to deflect our course, // false if all is well. //----------------------------------------------------------------------------- bool CNPC_Crow::Probe( const Vector &vecMoveDir, float flSpeed, Vector &vecDeflect ) { // // Look 1/2 second ahead. // trace_t tr; AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + vecMoveDir * flSpeed, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, HL2COLLISION_GROUP_CROW, &tr ); if ( tr.fraction < 1.0f ) { // // If we hit something, deflect flight path parallel to surface hit. // Vector vecUp; CrossProduct( vecMoveDir, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); return true; } vecDeflect = vec3_origin; return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- int CNPC_Houndeye::RangeAttack1Conditions ( float flDot, float flDist ) { // I'm not allowed to attack if standing in another hound eye // (note houndeyes allowed to interpenetrate) trace_t tr; AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,0.1), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { CBaseEntity *pEntity = tr.m_pEnt; if (pEntity->Classify() == CLASS_HOUNDEYE) { return( COND_NONE ); } } // If I'm really close to my enemy allow me to attack if // I'm facing regardless of next attack time if (flDist < 100 && flDot >= 0.3) { return COND_CAN_RANGE_ATTACK1; } if ( gpGlobals->curtime < m_flNextAttack ) { return( COND_NONE ); } if (flDist > ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 )) { return COND_TOO_FAR_TO_ATTACK; } if (flDot < 0.3) { return COND_NOT_FACING_ATTACK; } return COND_CAN_RANGE_ATTACK1; }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_AlienGrunt::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case AGRUNT_AE_HORNET1: case AGRUNT_AE_HORNET2: case AGRUNT_AE_HORNET3: case AGRUNT_AE_HORNET4: case AGRUNT_AE_HORNET5: { // m_vecEnemyLKP should be center of enemy body Vector vecArmPos; QAngle angArmDir; Vector vecDirToEnemy; QAngle angDir; if (HasCondition( COND_SEE_ENEMY) && GetEnemy()) { Vector vecEnemyLKP = GetEnemy()->GetAbsOrigin(); vecDirToEnemy = ( ( vecEnemyLKP ) - GetAbsOrigin() ); VectorAngles( vecDirToEnemy, angDir ); VectorNormalize( vecDirToEnemy ); } else { angDir = GetAbsAngles(); angDir.x = -angDir.x; Vector vForward; AngleVectors( angDir, &vForward ); vecDirToEnemy = vForward; } DoMuzzleFlash(); // make angles +-180 if (angDir.x > 180) { angDir.x = angDir.x - 360; } // SetBlending( 0, angDir.x ); GetAttachment( "0", vecArmPos, angArmDir ); vecArmPos = vecArmPos + vecDirToEnemy * 32; CPVSFilter filter( GetAbsOrigin() ); te->Sprite( filter, 0.0, &vecArmPos, iAgruntMuzzleFlash, random->RandomFloat( 0.4, 0.8 ), 128 ); CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, QAngle( 0, 0, 0 ), this ); Vector vForward; AngleVectors( angDir, &vForward ); pHornet->SetAbsVelocity( vForward * 300 ); pHornet->SetOwnerEntity( this ); EmitSound( "Weapon_Hornetgun.Single" ); CHL1BaseNPC *pHornetMonster = (CHL1BaseNPC *)pHornet->MyNPCPointer(); if ( pHornetMonster ) { pHornetMonster->SetEnemy( GetEnemy() ); } } break; case AGRUNT_AE_LEFT_FOOT: // left foot { CPASAttenuationFilter filter2( this ); EmitSound( filter2, entindex(), "AlienGrunt.LeftFoot" ); } break; case AGRUNT_AE_RIGHT_FOOT: // right foot { CPASAttenuationFilter filter3( this ); EmitSound( filter3, entindex(), "AlienGrunt.RightFoot" ); } break; case AGRUNT_AE_LEFT_PUNCH: { Vector vecMins = GetHullMins(); Vector vecMaxs = GetHullMaxs(); vecMins.z = vecMins.x; vecMaxs.z = vecMaxs.x; CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB ); CPASAttenuationFilter filter4( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( -25, 8, 0) ); Vector vRight; AngleVectors( GetAbsAngles(), NULL, &vRight, NULL ); // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * 250 ); } EmitSound(filter4, entindex(), "AlienGrunt.AttackHit" ); Vector vecArmPos; QAngle angArmAng; GetAttachment( 0, vecArmPos, angArmAng ); SpawnBlood(vecArmPos, g_vecAttackDir, pHurt->BloodColor(), 25);// a little surface blood. } else { // Play a random attack miss sound EmitSound(filter4, entindex(), "AlienGrunt.AttackMiss" ); } } break; case AGRUNT_AE_RIGHT_PUNCH: { Vector vecMins = GetHullMins(); Vector vecMaxs = GetHullMaxs(); vecMins.z = vecMins.x; vecMaxs.z = vecMaxs.x; CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB ); CPASAttenuationFilter filter5( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 25, 8, 0) ); // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. Vector vRight; AngleVectors( GetAbsAngles(), NULL, &vRight, NULL ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * -250 ); } EmitSound( filter5, entindex(), "AlienGrunt.AttackHit" ); Vector vecArmPos; QAngle angArmAng; GetAttachment( 0, vecArmPos, angArmAng ); SpawnBlood(vecArmPos, g_vecAttackDir, pHurt->BloodColor(), 25);// a little surface blood. } else { // Play a random attack miss sound EmitSound( filter5, entindex(), "AlienGrunt.AttackMiss" ); } } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Input : &Steer - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CNPC_Ichthyosaur::SteerAvoidObstacles(Vector &Steer, const Vector &Velocity, const Vector &Forward, const Vector &Right, const Vector &Up) { trace_t tr; bool collided = false; Vector dir = Velocity; float speed = VectorNormalize( dir ); //Look ahead one second and avoid whatever is in our way. AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + (dir*speed), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); Vector forward; GetVectors( &forward, NULL, NULL ); //If we're hitting our enemy, just continue on if ( ( GetEnemy() != NULL ) && ( tr.m_pEnt == GetEnemy() ) ) return false; if ( tr.fraction < 1.0f ) { CBaseEntity *pBlocker = tr.m_pEnt; if ( ( pBlocker != NULL ) && ( pBlocker->MyNPCPointer() != NULL ) ) { DevMsg( 2, "Avoiding an NPC\n" ); Vector HitOffset = tr.endpos - GetAbsOrigin(); Vector SteerUp = CrossProduct( HitOffset, Velocity ); Steer = CrossProduct( SteerUp, Velocity ); VectorNormalize( Steer ); /*Vector probeDir = tr.endpos - GetAbsOrigin(); Vector normalToProbeAndWallNormal = probeDir.Cross( tr.plane.normal ); Steer = normalToProbeAndWallNormal.Cross( probeDir ); VectorNormalize( Steer );*/ if ( tr.fraction > 0 ) { Steer = (Steer * Velocity.Length()) / tr.fraction; //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } else { Steer = (Steer * 1000 * Velocity.Length()); //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } } else { if ( ( pBlocker != NULL ) && ( pBlocker == GetEnemy() ) ) { DevMsg( "Avoided collision\n" ); return false; } DevMsg( 2, "Avoiding the world\n" ); Vector steeringVector = tr.plane.normal; if ( tr.fraction == 0.0f ) return false; Steer = steeringVector * ( Velocity.Length() / tr.fraction ); //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } //return true; collided = true; } //Try to remain 8 feet above the ground. AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -ICH_HEIGHT_PREFERENCE), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0f ) { Steer += Vector( 0, 0, m_vecAccelerationMax.z / tr.fraction ); collided = true; } //Stay under the surface if ( m_bIgnoreSurface == false ) { float waterLevel = ( UTIL_WaterLevel( GetAbsOrigin(), GetAbsOrigin().z, GetAbsOrigin().z+ICH_DEPTH_PREFERENCE ) - GetAbsOrigin().z ) / ICH_DEPTH_PREFERENCE; if ( waterLevel < 1.0f ) { Steer += -Vector( 0, 0, m_vecAccelerationMax.z / waterLevel ); collided = true; } } return collided; }
Vector CNPC_Ichthyosaur::DoProbe( const Vector &probe ) { trace_t tr; float fraction = 1.0f; bool collided = false; Vector normal = Vector( 0, 0, -1 ); float waterLevel = UTIL_WaterLevel( GetAbsOrigin(), GetAbsOrigin().z, GetAbsOrigin().z+150 ); waterLevel -= GetAbsOrigin().z; waterLevel /= 150; if ( waterLevel < 1.0f ) { collided = true; fraction = waterLevel; } AI_TraceHull( GetAbsOrigin(), probe, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( ( collided == false ) || ( tr.fraction < fraction ) ) { fraction = tr.fraction; normal = tr.plane.normal; } if ( ( fraction < 1.0f ) && ( GetEnemy() == NULL || tr.u.ent != GetEnemy()->pev ) ) { #if FEELER_COLLISION_VISUALIZE NDebugOverlay::Line( GetLocalOrigin(), probe, 255, 0, 0, false, 0.1f ); #endif Vector probeDir = probe - GetLocalOrigin(); Vector normalToProbeAndWallNormal = probeDir.Cross( normal ); Vector steeringVector = normalToProbeAndWallNormal.Cross( probeDir ); Vector velDir = GetAbsVelocity(); VectorNormalize( velDir ); float steeringForce = m_flGroundSpeed * ( 1.0f - fraction ) * normal.Dot( velDir ); if ( steeringForce < 0.0f ) { steeringForce = -steeringForce; } velDir = steeringVector; VectorNormalize( velDir ); steeringVector = steeringForce * velDir; return steeringVector; } #if FEELER_COLLISION_VISUALIZE NDebugOverlay::Line( GetLocalOrigin(), probe, 0, 255, 0, false, 0.1f ); #endif return Vector( 0.0f, 0.0f, 0.0f ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); //Ambient sounds /* if ( random->RandomInt( 0, 20 ) == 10 ) { if ( random->RandomInt( 0, 1 ) ) { ENVELOPE_CONTROLLER.SoundChangeVolume( m_pSwimSound, random->RandomFloat( 0.0f, 0.5f ), 1.0f ); } else { ENVELOPE_CONTROLLER.SoundChangeVolume( m_pVoiceSound, random->RandomFloat( 0.0f, 0.5f ), 1.0f ); } } */ //Pings if ( m_flNextPingTime < gpGlobals->curtime ) { m_flNextPingTime = gpGlobals->curtime + random->RandomFloat( 3.0f, 8.0f ); } //Growls if ( ( m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT ) && ( m_flNextGrowlTime < gpGlobals->curtime ) ) { m_flNextGrowlTime = gpGlobals->curtime + random->RandomFloat( 2.0f, 6.0f ); } //Randomly emit bubbles if ( random->RandomInt( 0, 10 ) == 0 ) { UTIL_Bubbles( GetAbsOrigin()+(GetHullMins()*0.5f), GetAbsOrigin()+(GetHullMaxs()*0.5f), 1 ); } //Check our water level if ( GetWaterLevel() != 3 ) { if ( GetWaterLevel() < 2 ) { DevMsg( 2, "Came out of water\n" ); if ( Beached() ) { SetSchedule( SCHED_ICH_THRASH ); Vector vecNewVelocity = GetAbsVelocity(); vecNewVelocity[2] = 8.0f; SetAbsVelocity( vecNewVelocity ); } } else { //TODO: Wake effects } } //If we have a victim, update them if ( m_pVictim != NULL ) { //See if it's time to release the victim if ( m_flHoldTime < gpGlobals->curtime ) { ReleaseVictim(); return; } Bite(); } }
//========================================================= // SelectSchedule //========================================================= int CNPC_Houndeye::SelectSchedule( void ) { switch ( m_NPCState ) { case NPC_STATE_IDLE: case NPC_STATE_ALERT: { if ( HasCondition(COND_LIGHT_DAMAGE) || HasCondition(COND_HEAVY_DAMAGE) ) { return SCHED_TAKE_COVER_FROM_ORIGIN; } break; } case NPC_STATE_COMBAT: { // dead enemy if ( HasCondition( COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. return BaseClass::SelectSchedule(); } // If a group attack was requested attack even if attack conditions not met if ( HasCondition( COND_HOUND_GROUP_ATTACK )) { // Check that I'm not standing in another hound eye // before attacking trace_t tr; AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,1), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if (!tr.startsolid) { return SCHED_HOUND_GROUP_ATTACK; } // Otherwise attack as soon as I can else { m_flNextAttack = gpGlobals->curtime; SCHED_HOUND_ATTACK_STRAFE; } } // If a group retread was requested if ( HasCondition( COND_HOUND_GROUP_RETREAT )) { return SCHED_HOUND_GROUP_RETREAT; } if ( HasCondition( COND_LIGHT_DAMAGE ) | HasCondition( COND_HEAVY_DAMAGE ) ) { if ( random->RandomFloat( 0 , 1 ) <= 0.4 ) { trace_t tr; Vector forward; AngleVectors( GetAbsAngles(), &forward ); AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + forward * -128, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0 ) { // it's clear behind, so the hound will jump return SCHED_HOUND_HOP_RETREAT; } } return SCHED_TAKE_COVER_FROM_ENEMY; } // If a group rally was requested if ( HasCondition( COND_HOUND_GROUP_RALLEY )) { return SCHED_HOUND_GROUP_RALLEY; } if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) ) { if (m_pSquad && random->RandomInt(0,4) == 0) { if (!IsAnyoneInSquadAttacking()) { EmitSound( "NPC_Houndeye.GroupAttack" ); m_flSoundWaitTime = gpGlobals->curtime + 1.0; m_pSquad->BroadcastInteraction( g_interactionHoundeyeGroupAttack, NULL, this ); return SCHED_HOUND_GROUP_ATTACK; } } //<<TEMP>>comment SetCollisionGroup( COLLISION_GROUP_NONE ); return SCHED_RANGE_ATTACK1; } else { if (m_pSquad && random->RandomInt(0,5) == 0) { if (!IsAnyoneInSquadAttacking()) { EmitSound( "NPC_Houndeye.GroupFollow" ); m_flSoundWaitTime = gpGlobals->curtime + 1.0; m_pSquad->BroadcastInteraction( g_interactionHoundeyeGroupRalley, NULL, this ); return SCHED_HOUND_ATTACK_STRAFE; } } return SCHED_HOUND_ATTACK_STRAFE; } break; } } return BaseClass::SelectSchedule(); }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_Vortigaunt::HandleAnimEvent( animevent_t *pEvent ) { // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); switch( pEvent->event ) { case ISLAVE_AE_CLAW: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 40, Vector(-10,-10,-10), Vector(10,10,10), sk_islave_dmg_claw.GetFloat(), DMG_SLASH ); CPASAttenuationFilter filter( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 5, 0, -18 ) ); // Play a random attack hit sound enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, pAttackHitSounds[ random->RandomInt(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_iVoicePitch ); } else // Play a random attack miss sound enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, pAttackMissSounds[ random->RandomInt(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_iVoicePitch ); } break; case ISLAVE_AE_CLAWRAKE: { CBaseEntity *pHurt = CheckTraceHullAttack( 40, Vector(-10,-10,-10), Vector(10,10,10), sk_islave_dmg_clawrake.GetFloat(), DMG_SLASH ); CPASAttenuationFilter filter2( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 5, 0, 18 ) ); enginesound->EmitSound( filter2, entindex(), CHAN_WEAPON, pAttackHitSounds[ random->RandomInt(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_iVoicePitch ); } else enginesound->EmitSound( filter2, entindex(), CHAN_WEAPON, pAttackMissSounds[ random->RandomInt(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_iVoicePitch ); } break; case ISLAVE_AE_ZAP_POWERUP: { // speed up attack when on hard if ( g_iSkillLevel == SKILL_HARD ) m_flPlaybackRate = 1.5; Vector v_forward; GetVectors( &v_forward, NULL, NULL ); CBroadcastRecipientFilter filter; te->DynamicLight( filter, 0.0, &GetAbsOrigin(), 125, 200, 100, 2, 120, 0.2 / m_flPlaybackRate, 0 ); if ( m_hDead != NULL ) { WackBeam( -1, m_hDead ); WackBeam( 1, m_hDead ); } else { ArmBeam( -1 ); ArmBeam( 1 ); BeamGlow( ); } CPASAttenuationFilter filter3( this ); enginesound->EmitSound( filter3, entindex(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); // Huh? Model doesn't have multiple texturegroups, commented this out. -LH // m_nSkin = m_iBeams / 2; } break; case ISLAVE_AE_ZAP_SHOOT: { ClearBeams( ); if ( m_hDead != NULL ) { Vector vecDest = m_hDead->GetAbsOrigin() + Vector( 0, 0, 38 ); trace_t trace; UTIL_TraceHull( vecDest, vecDest, GetHullMins(), GetHullMaxs(),MASK_SOLID, m_hDead, COLLISION_GROUP_NONE, &trace ); if ( !trace.startsolid ) { CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->GetAbsOrigin(), m_hDead->GetAbsAngles() ); pNew->AddSpawnFlags( 1 ); WackBeam( -1, pNew ); WackBeam( 1, pNew ); UTIL_Remove( m_hDead ); break; } } ClearMultiDamage(); ZapBeam( -1 ); ZapBeam( 1 ); CPASAttenuationFilter filter4( this ); enginesound->EmitSound( filter4, entindex(), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, random->RandomInt( 130, 160 ) ); ApplyMultiDamage(); m_flNextAttack = gpGlobals->curtime + random->RandomFloat( 0.5, 4.0 ); } break; case ISLAVE_AE_ZAP_DONE: { ClearBeams(); } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CASW_Alien_Jumper::ShouldJump( void ) { if ( GetEnemy() == NULL ) return false; // don't jump if we're stunned if (m_bElectroStunned) return false; //Too soon to try to jump if ( m_flJumpTime > gpGlobals->curtime ) return false; // only jump if you're on the ground if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP ) return false; // Don't jump if I'm not allowed if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false ) return false; Vector vEnemyForward, vForward; GetEnemy()->GetVectors( &vEnemyForward, NULL, NULL ); GetVectors( &vForward, NULL, NULL ); float flDot = DotProduct( vForward, vEnemyForward ); if ( flDot < 0.5f ) flDot = 0.5f; Vector vecPredictedPos; //Get our likely position in two seconds UTIL_PredictedPosition( GetEnemy(), flDot * 2.5f, &vecPredictedPos ); // Don't jump if we're already near the target if ( ( GetAbsOrigin() - vecPredictedPos ).LengthSqr() < (512*512) ) return false; //Don't retest if the target hasn't moved enough //FIXME: Check your own distance from last attempt as well if ( ( ( m_vecLastJumpAttempt - vecPredictedPos ).LengthSqr() ) < (128*128) ) { m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } Vector targetDir = ( vecPredictedPos - GetAbsOrigin() ); float flDist = VectorNormalize( targetDir ); // don't jump at target it it's very close if (flDist < ANTLION_JUMP_MIN) return false; Vector targetPos = vecPredictedPos + ( targetDir * (GetHullWidth()*4.0f) ); // Try the jump AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), targetPos, MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), targetPos, 255, 0, 0, 0, 5 ); } m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 ); } //Save this jump in case the next time fails m_vecSavedJump = moveTrace.vJumpVelocity; m_vecLastJumpAttempt = targetPos; return true; }