//----------------------------------------------------------------------------- // Purpose: // Output : CBaseCombatCharacter //----------------------------------------------------------------------------- CBaseCombatCharacter *CBaseGrenade::GetThrower( void ) { CBaseCombatCharacter *pResult = ToBaseCombatCharacter( m_hThrower ); if ( !pResult && GetOwnerEntity() != NULL ) { pResult = ToBaseCombatCharacter( GetOwnerEntity() ); } return pResult; }
//----------------------------------------------------------------------------- // Purpose: Override so give correct ammo // Input : pOther - the entity that touched me // Output : //----------------------------------------------------------------------------- void CWeaponMolotov::MolotovTouch( CBaseEntity *pOther ) { // --------------------------------------------------- // First give weapon to touching entity if allowed // --------------------------------------------------- BaseClass::DefaultTouch(pOther); // ---------------------------------------------------- // Give molotov ammo if touching client // ---------------------------------------------------- if (pOther->GetFlags() & FL_CLIENT) { // ------------------------------------------------ // If already owned weapon of this type remove me // ------------------------------------------------ CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther ); CWeaponMolotov* oldWeapon = (CWeaponMolotov*)pBCC->Weapon_OwnsThisType( GetClassname() ); if (oldWeapon != this) { UTIL_Remove( this ); } else { pBCC->GiveAmmo( 1, m_iSecondaryAmmoType ); SetThink (NULL); } } }
//----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- bool CWeapon_SLAM::CanAttachSLAM( void ) { CBaseCombatCharacter *pOwner = GetOwner(); if (!pOwner) { return false; } Vector vecSrc = pOwner->Weapon_ShootPosition( ); Vector vecAiming = pOwner->BodyDirection2D( ); trace_t tr; Vector vecEnd = vecSrc + (vecAiming * 42); UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); if (tr.fraction < 1.0) { // Don't attach to a living creature if (tr.m_pEnt) { CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); if (pBCC) { return false; } } return true; } else { return false; } }
//----------------------------------------------------------------------------- // Purpose: Override so give correct ammo // Input : pOther - the entity that touched me // Output : //----------------------------------------------------------------------------- void CWeapon_SLAM::SlamTouch( CBaseEntity *pOther ) { CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther ); // Can I even pick stuff up? if ( pBCC && !pBCC->IsAllowedToPickupWeapons() ) return; // --------------------------------------------------- // First give weapon to touching entity if allowed // --------------------------------------------------- BaseClass::DefaultTouch(pOther); // ---------------------------------------------------- // Give slam ammo if touching client // ---------------------------------------------------- if (pOther->GetFlags() & FL_CLIENT) { // ------------------------------------------------ // If already owned weapon of this type remove me // ------------------------------------------------ CWeapon_SLAM* oldWeapon = (CWeapon_SLAM*)pBCC->Weapon_OwnsThisType( GetClassname() ); if (oldWeapon != this) { UTIL_Remove( this ); } else { pBCC->GiveAmmo( 1, m_iSecondaryAmmoType ); SetThink(NULL); } } }
//Pose la mine sur son support une fois l'animation terminée void CWeaponMine::FinishAttach( void ){ CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); if (!pOwner) return; Vector vecSrc, vecAiming; vecSrc = pOwner->EyePosition(); QAngle angles = pOwner->GetLocalAngles(); AngleVectors( angles, &vecAiming ); trace_t tr; UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 60), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); if (tr.fraction < 1.0) { if (tr.m_pEnt) { //On attache pas la mine sur une entité vivante CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); if (pBCC){ m_bAttachMine = false; m_bNeedReload = true; return; } #ifndef CLIENT_DLL //On vérifie qu'il n 'y a pas déjà une mine sur le support visé CBaseEntity* pResult = gEntList.FindEntityByClassname(NULL,"npc_mine"); while (pResult) { if((pResult->GetAbsOrigin() - tr.endpos).Length() < MINE_DISTANCE){ m_bAttachMine = false; m_bNeedReload = true; return; } pResult = gEntList.FindEntityByClassname(pResult,"npc_mine"); } if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR)) { QAngle angles; VectorAngles(tr.plane.normal, angles); angles.x += 90; CBaseEntity *pEnt = CBaseEntity::Create( "npc_mine", tr.endpos + tr.plane.normal * 3, angles, NULL ); CNPCMine *pMine = (CNPCMine *)pEnt; pMine->m_hOwner = GetOwner(); ChooseMineColor(pMine); pMine->AttachToEntity( pEntity ); pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType ); } #endif } } m_bAttachMine = false; m_bNeedReload = true; }
//----------------------------------------------------------------------------- // Purpose: // Input : &inputdata - //----------------------------------------------------------------------------- void CPropVehiclePrisonerPod::InputEnterVehicleImmediate( inputdata_t &inputdata ) { if ( m_bEnterAnimOn ) return; // Try the activator first & use them if they are a player. CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator ); if ( pPassenger == NULL ) { // Activator was not a player, just grab the nearest player. // AI Patch Addition. pPassenger = UTIL_GetNearestPlayer(GetAbsOrigin()); // AI Patch Addition. if ( pPassenger == NULL ) return; } CBasePlayer *pPlayer = ToBasePlayer( pPassenger ); if ( pPlayer != NULL ) { if ( pPlayer->IsInAVehicle() ) { // Force the player out of whatever vehicle they are in. pPlayer->LeaveVehicle(); } pPlayer->GetInVehicle( GetServerVehicle(), VEHICLE_ROLE_DRIVER ); } else { // NPCs are not currently supported - jdw Assert( 0 ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : &inputdata - //----------------------------------------------------------------------------- void CPropVehicleChoreoGeneric::InputEnterVehicleImmediate( inputdata_t &inputdata ) { if ( m_bEnterAnimOn ) return; // Try the activator first & use them if they are a player. CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator ); if ( pPassenger == NULL ) { // Activator was not a player, just grab the singleplayer player. pPassenger = UTIL_PlayerByIndex( 1 ); if ( pPassenger == NULL ) return; } CBasePlayer *pPlayer = ToBasePlayer( pPassenger ); if ( pPlayer != NULL ) { if ( pPlayer->IsInAVehicle() ) { // Force the player out of whatever vehicle they are in. pPlayer->LeaveVehicle(); } pPlayer->GetInVehicle( GetServerVehicle(), VEHICLE_ROLE_DRIVER ); } else { // NPCs not supported yet - jdw Assert( 0 ); } }
void CWeaponMine::MineTouch( CBaseEntity *pOther ) { #ifdef GAME_DLL CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther ); if ( pBCC && !pBCC->IsAllowedToPickupWeapons() ) return; #endif BaseClass::DefaultTouch(pOther); }
void CTripmineGrenade::BeamBreakThink( void ) { // See if I can go solid yet (has dropper moved out of way?) if (IsSolidFlagSet( FSOLID_NOT_SOLID )) { trace_t tr; Vector vUpBit = GetAbsOrigin(); vUpBit.z += 5.0; UTIL_TraceEntity( this, GetAbsOrigin(), vUpBit, MASK_SHOT, &tr ); if ( !tr.startsolid && (tr.fraction == 1.0) ) { RemoveSolidFlags( FSOLID_NOT_SOLID ); } } trace_t tr; // NOT MASK_SHOT because we want only simple hit boxes UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); // respawn detect. if ( !m_pBeam ) { MakeBeam( ); if ( tr.m_pEnt ) m_hOwner = tr.m_pEnt; // reset owner too } CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); bool bAttachMoved = false; if ( m_bAttached && m_hAttachEntity.Get() != NULL ) { if ( m_hAttachEntity.Get()->GetAbsOrigin() != m_vAttachedPosition ) bAttachMoved = true; } // Also blow up if the attached entity goes away, ie: a crate if (pBCC || fabs( m_flBeamLength - tr.fraction ) > 0.001 || ( m_bAttached && m_hAttachEntity.Get() == NULL) || bAttachMoved ) { m_iHealth = 0; if (m_pConstraint) m_pConstraint->Deactivate(); Event_Killed( CTakeDamageInfo( (CBaseEntity*)m_hOwner, this, 100, GIB_NORMAL ) ); return; } SetNextThink( gpGlobals->curtime + 0.05f ); }
bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) { // Get the entity because the weapon doesn't have the right angles. C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() ); if ( pEnt ) { if ( pEnt == C_BasePlayer::GetLocalPlayer() ) { vAngles = pEnt->EyeAngles(); } else { vAngles = pEnt->GetRenderAngles(); } } else { vAngles.Init(); } C_BasePlayer *player = ToBasePlayer( pEnt ); bool bUseViewModel = false; if ( C_BasePlayer::IsLocalPlayer( pEnt ) ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pEnt ); bUseViewModel = !player->ShouldDrawLocalPlayer(); } QAngle vDummy; if ( IsActiveByLocalPlayer() && bUseViewModel ) { C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { int iAttachment = vm->LookupAttachment( "muzzle" ); if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } } else { // Thirdperson int iAttachment = LookupAttachment( "muzzle" ); if ( GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } vOrigin = GetRenderOrigin(); return false; }
//----------------------------------------------------------------------------- // Purpose: Determine if we can jump to be on the enemy's vehicle // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- inline bool CAI_PassengerBehaviorZombie::CanBeOnEnemyVehicle( void ) { CBaseCombatCharacter *pEnemy = ToBaseCombatCharacter( GetOuter()->GetEnemy() ); if ( pEnemy != NULL ) { IServerVehicle *pVehicle = pEnemy->GetVehicle(); if ( pVehicle && pVehicle->NPC_HasAvailableSeat( GetRoleName() ) ) return true; } return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : &position - // &angles - // &velocity - // &angVelocity - // *owner - // Output : CBaseGrenade //----------------------------------------------------------------------------- CGrenadeBugBait *BugBaitGrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const QAngle &angVelocity, CBaseEntity *owner ) { CGrenadeBugBait *pGrenade = (CGrenadeBugBait *) CBaseEntity::Create( "npc_grenade_bugbait", position, angles, owner ); if ( pGrenade != NULL ) { pGrenade->SetLocalAngularVelocity( angVelocity ); pGrenade->SetAbsVelocity( velocity ); pGrenade->SetThrower( ToBaseCombatCharacter( owner ) ); } return pGrenade; }
CBaseGrenade *Fraggrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float timer, bool combineSpawned ) { // Don't set the owner here, or the player can't interact with grenades he's thrown CGrenadeFrag *pGrenade = (CGrenadeFrag *)CBaseEntity::Create( "npc_grenade_frag", position, angles, pOwner ); pGrenade->SetTimer( timer, timer - 1.5f ); pGrenade->SetVelocity( velocity, angVelocity ); pGrenade->SetThrower( ToBaseCombatCharacter( pOwner ) ); pGrenade->m_takedamage = DAMAGE_EVENTS_ONLY; pGrenade->SetCombineSpawned( combineSpawned ); return pGrenade; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseGrenade *HopWire_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float timer ) { CGrenadeHopwire *pGrenade = (CGrenadeHopwire *) CBaseEntity::Create( "npc_grenade_hopwire", position, angles, pOwner ); // Only set ourselves to detonate on a timer if we're not a trap hopwire if ( hopwire_trap.GetBool() == false ) { pGrenade->SetTimer( timer ); } pGrenade->SetVelocity( velocity, angVelocity ); pGrenade->SetThrower( ToBaseCombatCharacter( pOwner ) ); return pGrenade; }
//----------------------------------------------------------------------------- // Purpose: Override so give correct ammo // Input : pOther - the entity that touched me // Output : //----------------------------------------------------------------------------- void CWeapon_SLAM::SlamTouch( CBaseEntity *pOther ) { #ifdef GAME_DLL CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther ); // Can I even pick stuff up? if ( pBCC && !pBCC->IsAllowedToPickupWeapons() ) return; #endif // --------------------------------------------------- // First give weapon to touching entity if allowed // --------------------------------------------------- BaseClass::DefaultTouch(pOther); }
void CTripmineGrenade::BeamBreakThink( void ) { // See if I can go solid yet (has dropper moved out of way?) if (IsSolidFlagSet( FSOLID_NOT_SOLID )) { trace_t tr; Vector vUpBit = GetAbsOrigin(); vUpBit.z += 5.0; UTIL_TraceEntity( this, GetAbsOrigin(), vUpBit, MASK_SHOT, &tr ); if ( !tr.startsolid && (tr.fraction == 1.0) ) { RemoveSolidFlags( FSOLID_NOT_SOLID ); } } trace_t tr; // NOT MASK_SHOT because we want only simple hit boxes UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); // respawn detect. if ( !m_pBeam ) { MakeBeam( ); if ( tr.m_pEnt ) m_hOwner = tr.m_pEnt; // reset owner too } CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); if (pBCC && pBCC->GetTeamNumber() != m_nTeam && pBCC->m_floatCloakFactor < 1.0f) //if (pBCC || fabs( m_flBeamLength - tr.fraction ) > 0.001) { m_iHealth = 0; Event_Killed( CTakeDamageInfo( (CBaseEntity*)m_hOwner, this, 100, GIB_NORMAL ) ); return; } SetNextThink( gpGlobals->curtime + 0.05f ); }
bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) { // Get the entity because the weapon doesn't have the right angles. C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() ); if ( pEnt ) { if ( pEnt == C_BasePlayer::GetLocalPlayer() ) { vAngles = pEnt->EyeAngles(); } else { vAngles = pEnt->GetRenderAngles(); } } else { vAngles.Init(); } QAngle vDummy; if ( IsActiveByLocalPlayer() && !input->CAM_IsThirdPerson() ) { C_BasePlayer *player = ToBasePlayer( pEnt ); C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { int iAttachment = vm->LookupAttachment( "muzzle" ); if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } } else { // Thirdperson int iAttachment = LookupAttachment( "muzzle" ); if ( GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } vOrigin = GetRenderOrigin(); return false; }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CBaseSDKBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity, bool bIsSecondary ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); //Do view kick AddViewKick(); //Make sound for the AI CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, traceHit.endpos, 400, 0.2f, pPlayer ); // This isn't great, but it's something for when the crowbar hits. pPlayer->RumbleEffect( RUMBLE_AR2, 0, RUMBLE_FLAG_RESTART ); CBaseEntity *pHitEntity = traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); if( pPlayer && pHitEntity->IsNPC() ) { // If bonking an NPC, adjust damage. info.AdjustPlayerDamageInflictedForSkillLevel(); } CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit ); ApplyMultiDamage(); // Now hit all triggers along the ray that... TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection ); if ( ToBaseCombatCharacter( pHitEntity ) ) { gamestats->Event_WeaponHit( pPlayer, !bIsSecondary, GetClassname(), info ); } } // Apply an impact effect ImpactEffect( traceHit ); }
//----------------------------------------------------------------------------- // Purpose: Catch stalker specific messages // Input : // Output : //----------------------------------------------------------------------------- void CNPC_Stalker::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->Event() ) { case NPC_EVENT_LEFTFOOT: { EmitSound( "NPC_Stalker.FootstepLeft", pEvent->eventtime ); } break; case NPC_EVENT_RIGHTFOOT: { EmitSound( "NPC_Stalker.FootstepRight", pEvent->eventtime ); } break; case STALKER_AE_MELEE_HIT: { CBaseEntity *pHurt; pHurt = CheckTraceHullAttack( 32, Vector(-16,-16,-16), Vector(16,16,16), sk_stalker_melee_dmg.GetFloat(), DMG_SLASH ); if ( pHurt ) { if ( pHurt->GetFlags() & (FL_NPC|FL_CLIENT) ) { pHurt->ViewPunch( QAngle( 5, 0, random->RandomInt(-10,10)) ); } // Spawn some extra blood if we hit a BCC CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pHurt ); if (pBCC) { SpawnBlood(pBCC->EyePosition(), g_vecAttackDir, pBCC->BloodColor(), sk_stalker_melee_dmg.GetFloat()); } // Play a attack hit sound EmitSound( "NPC_Stalker.Hit" ); } break; } default: BaseClass::HandleAnimEvent( pEvent ); break; } }
void CTripmineGrenade::MakeBeam( void ) { trace_t tr; UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); m_flBeamLength = tr.fraction; // If I hit a living thing, send the beam through me so it turns on briefly // and then blows the living thing up CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); // Draw length is not the beam length if entity is in the way float drawLength = tr.fraction; if (pBCC) { SetOwnerEntity( pBCC ); UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); m_flBeamLength = tr.fraction; SetOwnerEntity( NULL ); } // set to follow laser spot SetThink( &CTripmineGrenade::BeamBreakThink ); // Delay first think slightly so beam has time // to appear if person right in front of it SetNextThink( gpGlobals->curtime + 1.0f ); Vector vecTmpEnd = GetLocalOrigin() + m_vecDir * 2048 * drawLength; m_pBeam = CBeam::BeamCreate( g_pModelNameLaser, 0.35 ); m_pBeam->PointEntInit( vecTmpEnd, this ); m_pBeam->SetColor( 255, 55, 52 ); m_pBeam->SetScrollRate( 25.6 ); m_pBeam->SetBrightness( 64 ); int beamAttach = LookupAttachment("beam_attach"); m_pBeam->SetEndAttachment( beamAttach ); }
//----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- bool CWeapon_SLAM::CanAttachSLAM( void ) { CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); if (!pOwner) { return false; } Vector vecSrc, vecAiming; // Take the eye position and direction vecSrc = pOwner->EyePosition(); QAngle angles = pOwner->GetLocalAngles(); AngleVectors( angles, &vecAiming ); trace_t tr; Vector vecEnd = vecSrc + (vecAiming * 42); UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); if (tr.fraction < 1.0) { // Don't attach to a living creature if (tr.m_pEnt) { CBaseEntity *pEntity = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); if (pBCC) { return false; } } return true; } else { return false; } }
//----------------------------------------------------------------------------- // Purpose: Override so can handle LOS to m_pScriptedTarget // Input : // Output : //----------------------------------------------------------------------------- bool CNPC_Stalker::InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- // Base class version assumes innate weapon position is at eye level Vector barrelPos = LaserStartPosition(ownerPos); trace_t tr; AI_TraceLine( barrelPos, targetPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { return true; } CBaseEntity *pBE = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pBE ); if ( pBE == GetEnemy() ) { return true; } else if (pBCC) { if (IRelationType( pBCC ) == D_HT) { return true; } else if (bSetConditions) { SetCondition(COND_WEAPON_BLOCKED_BY_FRIEND); } } else if (bSetConditions) { SetCondition(COND_WEAPON_SIGHT_OCCLUDED); SetEnemyOccluder(pBE); } return false; }
void CGrenadeMP5::GrenadeMP5Touch( CBaseEntity *pOther ) { if ( !pOther->IsSolid() ) return; // If I'm live go ahead and blow up if (m_bIsLive) { Detonate(); } else { // If I'm not live, only blow up if I'm hitting an chacter that // is not the owner of the weapon CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pOther ); if (pBCC && GetThrower() != pBCC) { m_bIsLive = true; Detonate(); } } }
//----------------------------------------------------------------------------- // Purpose: Force the player to enter the vehicle. //----------------------------------------------------------------------------- void CPropVehicleChoreoGeneric::InputEnterVehicle( inputdata_t &inputdata ) { if ( m_bEnterAnimOn ) return; // Try the activator first & use them if they are a player. CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator ); if ( pPassenger == NULL ) { // Activator was not a player, just grab the singleplayer player. pPassenger = UTIL_PlayerByIndex( 1 ); if ( pPassenger == NULL ) return; } // FIXME: I hate code like this. I should really add a parameter to HandlePassengerEntry // to allow entry into locked vehicles bool bWasLocked = m_bLocked; m_bLocked = false; GetServerVehicle()->HandlePassengerEntry( pPassenger, true ); m_bLocked = bWasLocked; }
//----------------------------------------------------------------------------- // Purpose: Force the player to enter the vehicle. //----------------------------------------------------------------------------- void CPropVehiclePrisonerPod::InputEnterVehicle( inputdata_t &inputdata ) { if ( m_bEnterAnimOn ) return; // Try the activator first & use them if they are a player. CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator ); if ( pPassenger == NULL ) { // Activator was not a player, just grab the nearest player. // AI Patch Addition. pPassenger = UTIL_GetNearestPlayer(GetAbsOrigin()); // AI Patch Addition. if ( pPassenger == NULL ) return; } // FIXME: I hate code like this. I should really add a parameter to HandlePassengerEntry // to allow entry into locked vehicles bool bWasLocked = m_bLocked; m_bLocked = false; GetServerVehicle()->HandlePassengerEntry( pPassenger, true ); m_bLocked = bWasLocked; }
//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CASW_Weapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { bool bHasLOS = BaseClass::WeaponLOSCondition(ownerPos, targetPos, bSetConditions); // if the weapon has LOS, then do another wider trace to check we don't hit any friendlies // this is to stop the AI marines shooting way too close to other marines, which stops the player thinking about positioning so much if (bHasLOS && GetOwner() && asw_weapon_safety_hull.GetFloat() > 0) { CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer(); Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); // Find its relative shoot position Vector barrelPos = ownerPos + vecRelativeShootPosition; CASWWeaponLOSFilter traceFilter( GetOwner(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); // Use the custom LOS trace filter trace_t tr; UTIL_TraceHull( barrelPos, targetPos, Vector(-asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat()), Vector(asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat()), MASK_SHOT, &traceFilter, &tr ); if ( tr.fraction == 1.0 || tr.m_pEnt == npcOwner->GetEnemy() ) return true; // if a friendly is in the way, then we report failure CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt ); if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } return false; } } return bHasLOS; }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } //gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
//------------------------------------------------------------------------------ // Purpose : Draw attack beam and do damage / decals // Input : // Output : //------------------------------------------------------------------------------ void CNPC_Stalker::DrawAttackBeam(void) { if (!m_pBeam) return; // --------------------------------------------- // Get beam end point // --------------------------------------------- Vector vecSrc = LaserStartPosition(GetAbsOrigin()); trace_t tr; AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); CalcBeamPosition(); bool bInWater = (UTIL_PointContents ( tr.endpos, MASK_WATER ) & MASK_WATER)?true:false; // --------------------------------------------- // Update the beam position // --------------------------------------------- m_pBeam->SetStartPos( tr.endpos ); m_pBeam->RelinkBeam(); Vector vAttachPos; GetAttachment(STALKER_LASER_ATTACHMENT,vAttachPos); Vector vecAimDir = tr.endpos - vAttachPos; VectorNormalize( vecAimDir ); SetAim( vecAimDir ); // -------------------------------------------- // Play burn sounds // -------------------------------------------- CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt ); if (pBCC) { if (gpGlobals->curtime > m_fNextDamageTime) { ClearMultiDamage(); float damage = 0.0; switch (m_eBeamPower) { case STALKER_BEAM_LOW: damage = 1; break; case STALKER_BEAM_MED: damage = 3; break; case STALKER_BEAM_HIGH: damage = 10; break; } CTakeDamageInfo info( this, this, damage, DMG_SHOCK ); CalculateMeleeDamageForce( &info, m_vLaserDir, tr.endpos ); pBCC->DispatchTraceAttack( info, m_vLaserDir, &tr ); ApplyMultiDamage(); m_fNextDamageTime = gpGlobals->curtime + 0.1; } if (pBCC->Classify()!=CLASS_BULLSEYE) { if (!m_bPlayingHitFlesh) { CPASAttenuationFilter filter( m_pBeam,"NPC_Stalker.BurnFlesh" ); filter.MakeReliable(); EmitSound( filter, m_pBeam->entindex(),"NPC_Stalker.BurnFlesh" ); m_bPlayingHitFlesh = true; } if (m_bPlayingHitWall) { StopSound( m_pBeam->entindex(), "NPC_Stalker.BurnWall" ); m_bPlayingHitWall = false; } tr.endpos.z -= 24.0f; if (!bInWater) { DoSmokeEffect(tr.endpos + tr.plane.normal * 8); } } } if (!pBCC || pBCC->Classify()==CLASS_BULLSEYE) { if (!m_bPlayingHitWall) { CPASAttenuationFilter filter( m_pBeam, "NPC_Stalker.BurnWall" ); filter.MakeReliable(); EmitSound( filter, m_pBeam->entindex(), "NPC_Stalker.BurnWall" ); m_bPlayingHitWall = true; } if (m_bPlayingHitFlesh) { StopSound(m_pBeam->entindex(), "NPC_Stalker.BurnFlesh" ); m_bPlayingHitFlesh = false; } UTIL_DecalTrace( &tr, "RedGlowFade"); UTIL_DecalTrace( &tr, "FadingScorch" ); tr.endpos.z -= 24.0f; if (!bInWater) { DoSmokeEffect(tr.endpos + tr.plane.normal * 8); } } if (bInWater) { UTIL_Bubbles(tr.endpos-Vector(3,3,3),tr.endpos+Vector(3,3,3),10); } /* CBroadcastRecipientFilter filter; TE_DynamicLight( filter, 0.0, EyePosition(), 255, 0, 0, 5, 0.2, 0 ); */ }
//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer(); // Find its relative shoot position Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); Vector barrelPos = ownerPos + vecRelativeShootPosition; // Use the custom LOS trace filter CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); trace_t tr; UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr ); // See if we completed the trace without interruption if ( tr.fraction == 1.0 ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } CBaseEntity *pHitEnt = tr.m_pEnt; CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() ); // is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle) if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() ) { // Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is // Also, check to see if the owner of the entity is the vehicle, in which case it's valid too. // This catches vehicles that use bone followers. CBaseEntity *pVehicle = pEnemyPlayer->GetVehicle()->GetVehicleEnt(); if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle ) return true; } // Hitting our enemy is a success case if ( pHitEnt == npcOwner->GetEnemy() ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } // If a vehicle is blocking the view, grab its driver and use that as the combat character CBaseCombatCharacter *pBCC; IServerVehicle *pVehicle = pHitEnt->GetServerVehicle(); if ( pVehicle ) { pBCC = pVehicle->GetPassenger( ); } else { pBCC = ToBaseCombatCharacter( pHitEnt ); } if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } } else if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED ); npcOwner->SetEnemyOccluder( pHitEnt ); if( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 ); } } return false; }
//========================================================= // 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 ); } }