bool CNPC_Zombine::CanRunAScriptedNPCInteraction( bool bForced ) { if ( HasGrenade() == true ) return false; return BaseClass::CanRunAScriptedNPCInteraction( bForced ); }
void CNPC_Zombine::GatherGrenadeConditions( void ) { if ( m_iGrenadeCount <= 0 ) return; if ( g_flZombineGrenadeTimes > gpGlobals->curtime ) return; if ( m_flGrenadePullTime > gpGlobals->curtime ) return; if ( m_flSuperFastAttackTime >= gpGlobals->curtime ) return; if ( HasGrenade() ) return; if ( GetEnemy() == NULL ) return; if ( FVisible( GetEnemy() ) == false ) return; if ( IsSprinting() ) return; if ( IsOnFire() ) return; if ( IsRunningDynamicInteraction() == true ) return; if ( m_ActBusyBehavior.IsActive() ) return; CBasePlayer *pPlayer = AI_GetSinglePlayer(); if ( pPlayer && pPlayer->FVisible( this ) ) { float flLengthToPlayer = (pPlayer->GetAbsOrigin() - GetAbsOrigin()).Length(); float flLengthToEnemy = flLengthToPlayer; if ( pPlayer != GetEnemy() ) { flLengthToEnemy = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin()).Length(); } if ( flLengthToPlayer <= GRENADE_PULL_MAX_DISTANCE && flLengthToEnemy <= GRENADE_PULL_MAX_DISTANCE ) { float flPullChance = 1.0f - ( flLengthToEnemy / GRENADE_PULL_MAX_DISTANCE ); m_flGrenadePullTime = gpGlobals->curtime + 0.5f; if ( flPullChance >= random->RandomFloat( 0.0f, 1.0f ) ) { g_flZombineGrenadeTimes = gpGlobals->curtime + 10.0f; SetCondition( COND_ZOMBINE_GRENADE ); } } } }
void CNPC_Zombine::PrescheduleThink( void ) { GatherGrenadeConditions(); if( gpGlobals->curtime > m_flNextMoanSound ) { if( CanPlayMoanSound() ) { // Classic guy idles instead of moans. IdleSound(); m_flNextMoanSound = gpGlobals->curtime + random->RandomFloat( 10.0, 15.0 ); } else { m_flNextMoanSound = gpGlobals->curtime + random->RandomFloat( 2.5, 5.0 ); } } if ( HasGrenade () ) { CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetSmoothedVelocity() * 0.5f , 256, 0.1, this, SOUNDENT_CHANNEL_ZOMBINE_GRENADE ); if( IsSprinting() && GetEnemy() && GetEnemy()->Classify() == CLASS_PLAYER_ALLY_VITAL && HasCondition( COND_SEE_ENEMY ) ) { if( GetAbsOrigin().DistToSqr(GetEnemy()->GetAbsOrigin()) < Square( 144 ) ) { StopSprint(); } } } BaseClass::PrescheduleThink(); }
void CNPC_Zombine::ReleaseGrenade( Vector vPhysgunPos ) { if ( HasGrenade() == false ) return; Vector vDir = vPhysgunPos - m_hGrenade->GetAbsOrigin(); VectorNormalize( vDir ); Activity aActivity; Vector vForward, vRight; GetVectors( &vForward, &vRight, NULL ); float flDotForward = DotProduct( vForward, vDir ); float flDotRight = DotProduct( vRight, vDir ); bool bNegativeForward = false; bool bNegativeRight = false; if ( flDotForward < 0.0f ) { bNegativeForward = true; flDotForward = flDotForward * -1; } if ( flDotRight < 0.0f ) { bNegativeRight = true; flDotRight = flDotRight * -1; } if ( flDotRight > flDotForward ) { if ( bNegativeRight == true ) aActivity = (Activity)ACT_ZOMBINE_GRENADE_FLINCH_WEST; else aActivity = (Activity)ACT_ZOMBINE_GRENADE_FLINCH_EAST; } else { if ( bNegativeForward == true ) aActivity = (Activity)ACT_ZOMBINE_GRENADE_FLINCH_BACK; else aActivity = (Activity)ACT_ZOMBINE_GRENADE_FLINCH_FRONT; } AddGesture( aActivity ); DropGrenade( vec3_origin ); if ( IsSprinting() ) { StopSprint(); } else { Sprint(); } }
void CNPC_Zombine::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT_STEP: case TASK_WAIT_FOR_MOVEMENT: { BaseClass::RunTask( pTask ); if ( IsOnFire() && IsSprinting() ) { StopSprint(); } //Only do this if I have an enemy if ( GetEnemy() ) { if ( AllowedToSprint() == true ) { Sprint( ( GetHealth() <= GetMaxHealth() * 0.5f ) ); return; } if ( HasGrenade() ) { if ( IsSprinting() ) { GetNavigator()->SetMovementActivity( (Activity)ACT_ZOMBINE_GRENADE_RUN ); } else { GetNavigator()->SetMovementActivity( (Activity)ACT_ZOMBINE_GRENADE_WALK ); } return; } if ( GetNavigator()->GetMovementActivity() != ACT_WALK ) { if ( IsSprinting() == false ) { GetNavigator()->SetMovementActivity( ACT_WALK ); } } } else { GetNavigator()->SetMovementActivity( ACT_WALK ); } break; } default: { BaseClass::RunTask( pTask ); break; } } }
bool CNPC_Zombine::AllowedToSprint( void ) { if ( IsOnFire() ) return false; //If you're sprinting then there's no reason to sprint again. if ( IsSprinting() ) return false; int iChance = SPRINT_CHANCE_VALUE; //Secobmod FixMe ?? also changed to HL2MPRules CHL2_Player *pPlayer = dynamic_cast <CHL2_Player*> ( UTIL_GetNearestPlayer(GetAbsOrigin() )); //CHL2MP_Player *pPlayer = dynamic_cast<CHL2MP_Player *>( UTIL_GetNearestPlayer(GetAbsOrigin() ); if ( pPlayer ) { #ifdef MFS if ( HL2MPRules()->IsAlyxInDarknessMode() && pPlayer->FlashlightIsOn() == false ) #else if (IsAlyxInDarknessMode() && pPlayer->FlashlightIsOn() == false) #endif { iChance = SPRINT_CHANCE_VALUE_DARKNESS; } //Bigger chance of this happening if the player is not looking at the zombie if ( pPlayer->FInViewCone( this ) == false ) { iChance *= 2; } } if ( HasGrenade() ) { iChance *= 4; } //Below 25% health they'll always sprint if ( ( GetHealth() > GetMaxHealth() * 0.5f ) ) { if ( IsStrategySlotRangeOccupied( SQUAD_SLOT_ZOMBINE_SPRINT1, SQUAD_SLOT_ZOMBINE_SPRINT2 ) == true ) return false; if ( random->RandomInt( 0, 100 ) > iChance ) return false; if ( m_flSprintRestTime > gpGlobals->curtime ) return false; } float flLength = ( GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter() ).Length(); if ( flLength > MAX_SPRINT_DISTANCE ) return false; return true; }
void CNPC_Zombine::Event_Killed( const CTakeDamageInfo &info ) { BaseClass::Event_Killed( info ); if ( HasGrenade() ) { DropGrenade( vec3_origin ); } }
Activity CNPC_Zombine::NPC_TranslateActivity( Activity baseAct ) { if ( baseAct == ACT_MELEE_ATTACK1 ) { if ( m_flSuperFastAttackTime > gpGlobals->curtime || HasGrenade() ) { return (Activity)ACT_ZOMBINE_ATTACK_FAST; } } if ( baseAct == ACT_IDLE ) { if ( HasGrenade() ) { return (Activity)ACT_ZOMBINE_GRENADE_IDLE; } } return BaseClass::NPC_TranslateActivity( baseAct ); }
//----------------------------------------------------------------------------- // Purpose: This is a generic function (to be implemented by sub-classes) to // handle specific interactions between different types of characters // (For example the barnacle grabbing an NPC) // Input : Constant for the type of interaction // Output : true - if sub-class has a response for the interaction // false - if sub-class has no response //----------------------------------------------------------------------------- bool CNPC_Zombine::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ) { if ( interactionType == g_interactionBarnacleVictimGrab ) { if ( HasGrenade() ) { DropGrenade( vec3_origin ); } } return BaseClass::HandleInteraction( interactionType, data, sourceEnt ); }
void CNPC_Zombine::Event_Killed( const CTakeDamageInfo &info ) { CTakeDamageInfo dInfo = info; if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && info.GetDamageType() & (DMG_ALWAYSGIB | DMG_BLAST | DMG_CRUSH) && !(info.GetDamageType() & (DMG_DISSOLVE)) && !m_fIsTorso) { dInfo.SetDamageType(info.GetDamageType() | DMG_REMOVENORAGDOLL); } BaseClass::Event_Killed( dInfo ); if ( HasGrenade() ) { DropGrenade( vec3_origin ); } }
int CNPC_Zombine::MeleeAttack1Conditions ( float flDot, float flDist ) { int iBase = BaseClass::MeleeAttack1Conditions( flDot, flDist ); if( HasGrenade() ) { //Adrian: stop spriting if we get close enough to melee and we have a grenade //this gives NPCs time to move away from you (before it was almost impossible cause of the high sprint speed) if ( iBase == COND_CAN_MELEE_ATTACK1 ) { StopSprint(); } } return iBase; }
void CNPC_Zombine::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ) { BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator ); //Only knock grenades off their hands if it's a player doing the damage. if ( info.GetAttacker() && info.GetAttacker()->IsNPC() ) return; if ( info.GetDamageType() & ( DMG_BULLET | DMG_CLUB ) ) { if ( ptr->hitgroup == HITGROUP_LEFTARM ) { if ( HasGrenade() ) { DropGrenade( info.GetDamageForce() ); StopSprint(); } } } }
void CNPC_Zombine::Sprint( bool bMadSprint ) { if ( IsSprinting() ) return; OccupyStrategySlotRange( SQUAD_SLOT_ZOMBINE_SPRINT1, SQUAD_SLOT_ZOMBINE_SPRINT2 ); GetNavigator()->SetMovementActivity( ACT_RUN ); float flSprintTime = random->RandomFloat( MIN_SPRINT_TIME, MAX_SPRINT_TIME ); //If holding a grenade then sprint until it blows up. if ( HasGrenade() || bMadSprint == true ) { flSprintTime = 9999; } m_flSprintTime = gpGlobals->curtime + flSprintTime; //Don't sprint for this long after I'm done with this sprint run. m_flSprintRestTime = m_flSprintTime + random->RandomFloat( 2.5f, 5.0f ); EmitSound( "Zombine.Charge" ); }
void CNPC_Zombine::HandleAnimEvent( animevent_t *pEvent ) { if ( pEvent->event == AE_ZOMBINE_PULLPIN ) { Vector vecStart; QAngle angles; GetAttachment( "grenade_attachment", vecStart, angles ); CBaseGrenade *pGrenade = Fraggrenade_Create( vecStart, vec3_angle, vec3_origin, AngularImpulse( 0, 0, 0 ), this, 3.5f, true ); if ( pGrenade ) { // Move physobject to shadow IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject(); if ( pPhysicsObject ) { pGrenade->VPhysicsDestroyObject(); int iAttachment = LookupAttachment( "grenade_attachment"); pGrenade->SetMoveType( MOVETYPE_NONE ); pGrenade->SetSolid( SOLID_NONE ); pGrenade->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); pGrenade->SetAbsOrigin( vecStart ); pGrenade->SetAbsAngles( angles ); pGrenade->SetParent( this, iAttachment ); pGrenade->SetDamage( 200.0f ); m_hGrenade = pGrenade; EmitSound( "Zombine.ReadyGrenade" ); // Tell player allies nearby to regard me! CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); CAI_BaseNPC *pNPC; for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { pNPC = ppAIs[i]; if( pNPC->Classify() == CLASS_PLAYER_ALLY || pNPC->Classify() == CLASS_PLAYER_ALLY_VITAL && pNPC->FVisible(this) ) { int priority; Disposition_t disposition; priority = pNPC->IRelationPriority(this); disposition = pNPC->IRelationType(this); pNPC->AddEntityRelationship( this, disposition, priority + 1 ); } } } m_iGrenadeCount--; } return; } if ( pEvent->event == AE_NPC_ATTACK_BROADCAST ) { if ( HasGrenade() ) return; } BaseClass::HandleAnimEvent( pEvent ); }