//--------------------------------------------------------- // This starts the bullet state machine. The actual effects // of the bullet will happen later. This function schedules // those effects. // // fDirectShot indicates whether the bullet is a "direct shot" // that is - fired with the intent that it will strike the // enemy. Otherwise, the bullet is intended to strike a // decoy object or nothing at all in particular. //--------------------------------------------------------- bool CNPC_Combine_Cannon::FireBullet( const Vector &vecTarget, bool bDirectShot ) { Vector vecBulletOrigin = GetBulletOrigin(); Vector vecDir = ( vecTarget - vecBulletOrigin ); VectorNormalize( vecDir ); FireBulletsInfo_t info; info.m_iShots = 1; info.m_iTracerFreq = 1; info.m_vecDirShooting = vecDir; info.m_vecSrc = vecBulletOrigin; info.m_flDistance = MAX_TRACE_LENGTH; info.m_pAttacker = this; info.m_iAmmoType = m_iAmmoType; info.m_iPlayerDamage = 20; info.m_vecSpread = Vector( 0.015f, 0.015f, 0.015f ); // medium cone FireBullets( info ); EmitSound( "NPC_Combine_Cannon.FireBullet" ); // Don't attack for a certain amount of time SetNextAttack( gpGlobals->curtime + GetRefireTime() ); // Sniper had to be aiming here to fire here, so make it the cursor m_vecPaintCursor = vecTarget; LaserOff(); return true; }
void CNPC_ControllerHeadBall::HuntThink( void ) { SetNextThink( gpGlobals->curtime + 0.1 ); if( !m_pSprite ) { Assert(0); return; } m_pSprite->SetBrightness( m_pSprite->GetBrightness() - 5, 0.1f ); CBroadcastRecipientFilter filter; te->DynamicLight( filter, 0.0, &GetAbsOrigin(), 255, 255, 255, 0, m_pSprite->GetBrightness() / 16, 0.2, 0 ); // check world boundaries if (gpGlobals->curtime - m_flSpawnTime > 5 || m_pSprite->GetBrightness() < 64 /*|| GetEnemy() == NULL || m_hOwner == NULL*/ || !IsInWorld() ) { SetTouch( NULL ); SetThink( &CNPC_ControllerHeadBall::KillThink ); SetNextThink( gpGlobals->curtime ); return; } if( !GetEnemy() ) return; MovetoTarget( GetEnemy()->GetAbsOrigin() ); if ((GetEnemy()->WorldSpaceCenter() - GetAbsOrigin()).Length() < 64) { trace_t tr; UTIL_TraceLine( GetAbsOrigin(), GetEnemy()->WorldSpaceCenter(), MASK_ALL, this, COLLISION_GROUP_NONE, &tr ); CBaseEntity *pEntity = tr.m_pEnt; if (pEntity != NULL && pEntity->m_takedamage == DAMAGE_YES) { ClearMultiDamage( ); Vector dir = GetAbsVelocity(); VectorNormalize( dir ); CTakeDamageInfo info( this, this, sk_controller_dmgball.GetFloat(), DMG_SHOCK ); CalculateMeleeDamageForce( &info, dir, tr.endpos ); pEntity->DispatchTraceAttack( info, dir, &tr ); ApplyMultiDamage(); int haloindex = 0; int fadelength = 0; int amplitude = 0; const Vector vecEnd = tr.endpos; te->BeamEntPoint( filter, 0.0, entindex(), NULL, 0, &(tr.m_pEnt->GetAbsOrigin()), g_sModelIndexLaser, haloindex /* no halo */, 0, 10, 3, 20, 20, fadelength, amplitude, 255, 255, 255, 255, 10 ); } UTIL_EmitAmbientSound( GetSoundSourceIndex(), GetAbsOrigin(), "Controller.ElectroSound", 0.5, SNDLVL_NORM, 0, 100 ); SetNextAttack( gpGlobals->curtime + 3.0 ); SetThink( &CNPC_ControllerHeadBall::KillThink ); SetNextThink( gpGlobals->curtime + 0.3 ); } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CNPC_Bullsquid::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case BSQUID_AE_SPIT: { Vector vSpitPos; GetAttachment("mouth", vSpitPos); vSpitPos.z += 40.0f; Vector vTarget; // If our enemy is looking at us and far enough away, lead him if (HasCondition(COND_ENEMY_FACING_ME) && UTIL_DistApprox(GetAbsOrigin(), GetEnemy()->GetAbsOrigin()) > (40 * 12)) { UTIL_PredictedPosition(GetEnemy(), 0.5f, &vTarget); vTarget.z = GetEnemy()->GetAbsOrigin().z; } else { // Otherwise he can't see us and he won't be able to dodge vTarget = GetEnemy()->BodyTarget(vSpitPos, true); } vTarget[2] += random->RandomFloat(0.0f, 32.0f); // Try and spit at our target Vector vecToss; if (GetSpitVector(vSpitPos, vTarget, &vecToss) == false) { DevMsg("GetSpitVector( vSpitPos, vTarget, &vecToss ) == false\n"); // Now try where they were if (GetSpitVector(vSpitPos, m_vSavePosition, &vecToss) == false) { DevMsg("GetSpitVector( vSpitPos, m_vSavePosition, &vecToss ) == false\n"); // Failing that, just shoot with the old velocity we calculated initially! vecToss = m_vecSaveSpitVelocity; } } // Find what our vertical theta is to estimate the time we'll impact the ground Vector vecToTarget = (vTarget - vSpitPos); VectorNormalize(vecToTarget); float flVelocity = VectorNormalize(vecToss); float flCosTheta = DotProduct(vecToTarget, vecToss); float flTime = (vSpitPos - vTarget).Length2D() / (flVelocity * flCosTheta); // Emit a sound where this is going to hit so that targets get a chance to act correctly CSoundEnt::InsertSound(SOUND_DANGER, vTarget, (15 * 12), flTime, this); // Don't fire again until this volley would have hit the ground (with some lag behind it) SetNextAttack(gpGlobals->curtime + flTime + random->RandomFloat(0.5f, 2.0f)); for (int i = 0; i < 6; i++) { CGrenadeSpit *pGrenade = (CGrenadeSpit*)CreateEntityByName("grenade_spit"); pGrenade->SetAbsOrigin(vSpitPos); pGrenade->SetAbsAngles(vec3_angle); DispatchSpawn(pGrenade); pGrenade->SetThrower(this); pGrenade->SetOwnerEntity(this); if (i == 0) { pGrenade->SetSpitSize(SPIT_LARGE); pGrenade->SetAbsVelocity(vecToss * flVelocity); } else { pGrenade->SetAbsVelocity((vecToss + RandomVector(-0.035f, 0.035f)) * flVelocity); pGrenade->SetSpitSize(random->RandomInt(SPIT_SMALL, SPIT_MEDIUM)); } // Tumble through the air pGrenade->SetLocalAngularVelocity(QAngle(random->RandomFloat(-250, -500), random->RandomFloat(-250, -500), random->RandomFloat(-250, -500))); } for (int i = 0; i < 8; i++) { DispatchParticleEffect("blood_impact_yellow_01", vSpitPos + RandomVector(-12.0f, 12.0f), RandomAngle(0, 360)); } EmitSound("NPC_Antlion.PoisonShoot"); } break; case BSQUID_AE_BITE: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_bite.GetFloat(), DMG_SLASH ); if ( pHurt ) { Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); pHurt->ApplyAbsVelocityImpulse( 100 * (up-forward) ); pHurt->SetGroundEntity( NULL ); } } break; case BSQUID_AE_WHIP_SND: { EmitSound( "NPC_Bullsquid.TailWhip" ); break; } /* case BSQUID_AE_TAILWHIP: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_whip.GetFloat(), DMG_SLASH | DMG_ALWAYSGIB ); if ( pHurt ) { Vector right, up; AngleVectors( GetAbsAngles(), NULL, &right, &up ); if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 20, 0, -20 ) ); pHurt->ApplyAbsVelocityImpulse( 100 * (up+2*right) ); } } break; */ case BSQUID_AE_BLINK: { // close eye. m_nSkin = 1; } break; case BSQUID_AE_HOP: { float flGravity = GetCurrentGravity(); // throw the squid up into the air on this frame. if ( GetFlags() & FL_ONGROUND ) { SetGroundEntity( NULL ); } // jump 40 inches into the air Vector vecVel = GetAbsVelocity(); vecVel.z += sqrt( flGravity * 2.0 * 40 ); SetAbsVelocity( vecVel ); } break; case BSQUID_AE_THROW: { // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), 0, 0 ); if ( pHurt ) { pHurt->ViewPunch( QAngle(20,0,-20) ); // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. UTIL_ScreenShake( pHurt->GetAbsOrigin(), 25.0, 1.5, 0.7, 2, SHAKE_START ); // If the player, throw him around if ( pHurt->IsPlayer()) { Vector forward, up; AngleVectors( GetLocalAngles(), &forward, NULL, &up ); pHurt->ApplyAbsVelocityImpulse( forward * 300 + up * 300 ); } // If not the player see if has bullsquid throw interatcion else { CBaseCombatCharacter *pVictim = ToBaseCombatCharacter( pHurt ); if (pVictim) { if ( pVictim->DispatchInteraction( g_interactionBullsquidThrow, NULL, this ) ) { Vector forward, up; AngleVectors( GetLocalAngles(), &forward, NULL, &up ); pVictim->ApplyAbsVelocityImpulse( forward * 300 + up * 250 ); } } } } } break; default: BaseClass::HandleAnimEvent( pEvent ); } }