//----------------------------------------------------------------------------- // Purpose: Allows us to take damage from physics objects //----------------------------------------------------------------------------- void CBreakable::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) { BaseClass::VPhysicsCollision( index, pEvent ); Vector damagePos; pEvent->pInternalData->GetContactPoint( damagePos ); Vector damageForce = pEvent->postVelocity[index] * pEvent->pObjects[index]->GetMass(); if ( damageForce == vec3_origin ) { // This can happen if this entity is a func_breakable, and can't move. // Use the velocity of the entity that hit us instead. damageForce = pEvent->postVelocity[!index] * pEvent->pObjects[!index]->GetMass(); } // If we're supposed to explode on collision, do so if ( HasSpawnFlags( SF_BREAK_PHYSICS_BREAK_IMMEDIATELY ) ) { // We're toast m_bTookPhysicsDamage = true; CBaseEntity *pHitEntity = pEvent->pEntities[!index]; // HACKHACK: Reset mass to get correct collision response for the object breaking this glass if ( m_Material == matGlass ) { pEvent->pObjects[index]->SetMass( 2.0f ); } CTakeDamageInfo dmgInfo( pHitEntity, pHitEntity, damageForce, damagePos, (m_iHealth + 1), DMG_CRUSH ); PhysCallbackDamage( this, dmgInfo, *pEvent, index ); } else if ( !HasSpawnFlags( SF_BREAK_DONT_TAKE_PHYSICS_DAMAGE ) ) { int otherIndex = !index; CBaseEntity *pOther = pEvent->pEntities[otherIndex]; // We're to take normal damage from this int damageType; IBreakableWithPropData *pBreakableInterface = assert_cast<IBreakableWithPropData*>(this); float damage = CalculateDefaultPhysicsDamage( index, pEvent, m_impactEnergyScale, true, damageType, pBreakableInterface->GetPhysicsDamageTable() ); if ( damage > 0 ) { // HACKHACK: Reset mass to get correct collision response for the object breaking this glass if ( m_Material == matGlass ) { pEvent->pObjects[index]->SetMass( 2.0f ); } CTakeDamageInfo dmgInfo( pOther, pOther, damageForce, damagePos, damage, damageType ); PhysCallbackDamage( this, dmgInfo, *pEvent, index ); } } }
//=====================================================================================// // Purpose: Performs the screen shake and it checks to see if we hit an entity to // handle the proper damage // An entity here can be another player or a wood plank //=====================================================================================// void CTDPBludgeonWeaponBase::Hit( trace_t &tr, Activity nHitActivity ) { // Do we have a valid owner holding the weapon? CTDPPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; // Let's shake the screen a little AddViewKick(); // if tr.m_pEnt is not NULL it means we have hit a target if ( tr.m_pEnt != NULL ) { Vector vForward; pPlayer->EyeVectors( &vForward, NULL, NULL ); VectorNormalize( vForward ); // Process the damage and send it to the entity we just hit CTakeDamageInfo dmgInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); CalculateMeleeDamageForce( &dmgInfo, vForward, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, vForward, &tr ); ApplyMultiDamage(); #if defined( GAME_DLL ) // Now hit all triggers along the ray that... TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, vForward ); #endif } // Apply an impact effect ImpactEffect( tr ); }
void CNPC_Infected::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove ) { Vector vecForceDir; // Always hurt bullseyes for now if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, damage, DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); return; } CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f ); if ( pHurt ) { vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() ); //FIXME: Until the interaction is setup, kill combine soldiers in one hit -- jdw if ( FClassnameIs( pHurt, "npc_combine_s" ) ) { CTakeDamageInfo dmgInfo( this, this, pHurt->m_iHealth+25, DMG_SLASH ); CalculateMeleeDamageForce( &dmgInfo, vecForceDir, pHurt->GetAbsOrigin() ); pHurt->TakeDamage( dmgInfo ); return; } CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer != NULL ) { //Kick the player angles if ( !(pPlayer->GetFlags() & FL_GODMODE ) && pPlayer->GetMoveType() != MOVETYPE_NOCLIP ) { pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); //Push the target back pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] ); } } // Play a random attack hit sound EmitSound( "Zombie.Punch" ); } else { EmitSound( "Zombie.AttackMiss" ); } }
void CFlechette::DoAOEDamage() { CBaseEntity *ppEnts[256]; Vector vecCenter = WorldSpaceCenter(); float flRadius = flechette_radius.GetFloat(); vecCenter.z -= flRadius * 0.8f; int nEntCount = UTIL_EntitiesInSphere( ppEnts, 256, vecCenter, flRadius, 0 ); int i; for ( i = 0; i < nEntCount; i++ ) { if ( ppEnts[i] == NULL ) continue; bool bDoDamage = true; if(ppEnts[i]->IsPlayer() || ppEnts[i]->IsNPC()) { CBasePlayer *pOtherPlayer = ToBasePlayer(ppEnts[i]); CBasePlayer *pPlayer = ToBasePlayer(GetOwnerEntity()); if(pOtherPlayer != NULL && pPlayer != NULL) { if((HL2MPRules()->IsTeamplay() && (pPlayer->GetTeamNumber() == pOtherPlayer->GetTeamNumber())) || HL2MPRules()->GetGameType() == GAME_COOP) { const int oldHealth = pOtherPlayer->GetHealth(); pOtherPlayer->TakeHealth( HEAL_AMOUNT, DMG_GENERIC ); bDoDamage = false; if(oldHealth <= HEAL_AMOUNT) pOtherPlayer->PlayAutovocal(HEALED,0); if(oldHealth != pOtherPlayer->GetHealth()) // Si on a vraiment heal pOtherPlayer->EmitSound("Tranqu.Heal"); } } if(bDoDamage && ppEnts[i] != GetOwnerEntity()) { int iApplyDamage = 0; if(ppEnts[i]->IsNPC()) iApplyDamage = 70; else { if(ppEnts[i]->GetHealth() < m_iDamage + 10) iApplyDamage = 100; else iApplyDamage = ppEnts[i]->GetHealth() - m_iDamage; } CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), GetOwnerEntity(), iApplyDamage, DMG_POISON | DMG_NEVERGIB ); //CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( vecCenter ); ppEnts[i]->TakeDamage(dmgInfo); //ppEnts[i]->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } } ApplyMultiDamage(); } }
void ShootMe() { CASW_Player *pPlayer = ToASW_Player(UTIL_GetCommandClient()); if ( pPlayer->GetMarine() ) { CTakeDamageInfo dmgInfo( pPlayer, pPlayer, 3, DMG_BULLET ); Vector vecDir = RandomVector(-1, 1); trace_t tr; pPlayer->GetMarine()->DispatchTraceAttack( dmgInfo, vecDir, &tr ); } }
//========================================================= // Disparo //========================================================= void CWeaponGaussGun::Fire() { CBasePlayer *pOwner = ToBasePlayer(GetOwner()); // ¿El jugador no ha sido creado? if ( !pOwner ) return; m_bCharging = false; if ( m_hViewModel == NULL ) { CBaseViewModel *vm = pOwner->GetViewModel(); if ( vm ) m_hViewModel.Set(vm); } Vector startPos = pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector(AUTOAIM_5DEGREES); Vector vecUp, vecRight; VectorVectors(aimDir, vecRight, vecUp); float x, y, z; //Gassian spread do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); aimDir = aimDir + x * GetBulletSpread().x * vecRight + y * GetBulletSpread().y * vecUp; Vector endPos = startPos + (aimDir * MAX_TRACE_LENGTH); // Shoot a shot straight out trace_t tr; UTIL_TraceLine(startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr); #ifndef CLIENT_DLL ClearMultiDamage(); CBaseEntity *pHit = tr.m_pEnt; CTakeDamageInfo dmgInfo(this, pOwner, sk_plr_dmg_gauss.GetFloat(), DMG_SHOCK | DMG_DISSOLVE); if ( pHit != NULL ) { CalculateBulletDamageForce(&dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos); pHit->DispatchTraceAttack(dmgInfo, aimDir, &tr); } if ( tr.DidHitWorld() ) { float hitAngle = -DotProduct( tr.plane.normal, aimDir ); if ( hitAngle < 0.5f ) { Vector vReflection; vReflection = 2.0 * tr.plane.normal * hitAngle + aimDir; startPos = tr.endpos; endPos = startPos + (vReflection * MAX_TRACE_LENGTH); // Draw beam to reflection point DrawBeam(tr.startpos, tr.endpos, 15, true); CPVSFilter filter(tr.endpos); te->GaussExplosion(filter, 0.0f, tr.endpos, tr.plane.normal, 0); UTIL_ImpactTrace(&tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss"); //Find new reflection end position UTIL_TraceLine(startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr); if ( tr.m_pEnt != NULL ) { dmgInfo.SetDamageForce(GetAmmoDef()->DamageForce(m_iPrimaryAmmoType) * vReflection); dmgInfo.SetDamagePosition(tr.endpos); tr.m_pEnt->DispatchTraceAttack(dmgInfo, vReflection, &tr); } // Connect reflection point to end DrawBeam(tr.startpos, tr.endpos, 10); } else DrawBeam(tr.startpos, tr.endpos, 15, true); } else DrawBeam(tr.startpos, tr.endpos, 15, true); ApplyMultiDamage(); #endif UTIL_ImpactTrace(&tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss"); CPVSFilter filter(tr.endpos); te->GaussExplosion(filter, 0.0f, tr.endpos, tr.plane.normal, 0); m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; AddViewKick(); // Register a muzzleflash for the AI #ifndef CLIENT_DLL pOwner->SetMuzzleFlashTime(gpGlobals->curtime + 0.5); #endif }
void CASW_Shotgun_Pellet_Predicted::PelletTouch( CBaseEntity *pOther ) { if (!pOther) return; if (pOther == m_pLastHit) // don't damage the same alien twice return; if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) return; // make sure we don't die on things we shouldn't if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup())) return; if ( pOther->m_takedamage != DAMAGE_NO ) { trace_t tr, tr2; tr = BaseClass::GetTouchTrace(); Vector vecNormalizedVel = GetAbsVelocity(); VectorNormalize( vecNormalizedVel ); #ifdef GAME_DLL ClearMultiDamage(); if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() ) { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_NEVERGIB ); dmgInfo.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } else { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_BULLET | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } ApplyMultiDamage(); #endif //Adrian: keep going through the glass. if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return; // pellets should carry on through spawnable enemies? //IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pOther); //if (pSpawnable && asw_shotgun_pellets_pass.GetBool()) //{ //m_pLastHit = pOther; //return; //} SetAbsVelocity( Vector( 0, 0, 0 ) ); // play body "thwack" sound EmitSound( "Weapon_Crossbow.BoltHitBody" ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 ); #ifdef GAME_DLL if ( tr2.fraction != 1.0f ) { // NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 ); // NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 ); if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) ) { CEffectData data; data.m_vOrigin = tr2.endpos; data.m_vNormal = vForward; data.m_nEntIndex = tr2.fraction != 1.0f; //DispatchEffect( "BoltImpact", data ); } } #endif SetTouch( NULL ); SetThink( NULL ); //KillEffects(); //UTIL_Remove( this ); //Release(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime ); } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) ) { //EmitSound( "Weapon_Crossbow.BoltHitWorld" ); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); VectorNormalize( vecDir ); SetMoveType( MOVETYPE_NONE ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); #ifdef GAME_DLL CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; #endif //DispatchEffect( "BoltImpact", data ); UTIL_ImpactTrace( &tr, DMG_BULLET ); AddEffects( EF_NODRAW ); SetTouch( NULL ); //KillEffects(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); // Shoot some sparks #ifdef GAME_DLL if ( UTIL_PointContents( GetAbsOrigin(), CONTENTS_WATER ) != CONTENTS_WATER) { g_pEffects->Sparks( GetAbsOrigin() ); } #endif } else { // Put a mark unless we've hit the sky if ( ( tr.surface.flags & SURF_SKY ) == false ) { UTIL_ImpactTrace( &tr, DMG_BULLET ); } //KillEffects(); //UTIL_Remove( this ); //Release(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime ); } } }
void CGETKnife::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) { // Call the baseclass first so we don't interfere with the normal running of things BaseClass::VPhysicsCollision( index, pEvent ); // Grab what we hit CBaseEntity *pOther = pEvent->pEntities[!index]; if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) return; if ( !PassServerEntityFilter( this, pOther) ) return; if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) ) return; trace_t tr; CollisionEventToTrace( index, pEvent, tr ); Vector vecAiming = pEvent->preVelocity[index]; VectorNormalize( vecAiming ); if ( pOther->m_takedamage != DAMAGE_NO && (pOther->IsPlayer() || pOther->IsNPC()) ) { ClearMultiDamage(); CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), GetDamage(), DMG_SLASH | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecAiming, tr.endpos, TKNIFE_FORCE_SCALE ); dmgInfo.SetDamagePosition( tr.endpos ); if ( this->GetOwnerEntity() && this->GetOwnerEntity()->IsPlayer() ) { CBasePlayer *pPlayer = ToBasePlayer( this->GetOwnerEntity() ); dmgInfo.SetWeapon( pPlayer->Weapon_OwnsThisType( "weapon_throwing_knife" ) ); } pOther->DispatchTraceAttack( dmgInfo, vecAiming, &tr ); ApplyMultiDamage(); PhysCallbackSetVelocity( pEvent->pObjects[index], vec3_origin ); SetTouch( NULL ); SetThink( NULL ); PhysCallbackRemove( this->NetworkProp() ); } else { if ( pOther->IsWorld() ) { // We hit the world, we have to check if this is sky trace_t tr2; Vector origin; pEvent->pInternalData->GetContactPoint( origin ); UTIL_TraceLine( origin, origin + (vecAiming * 4), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr2 ); if ( tr2.surface.flags & SURF_SKY ) { // We hit sky, remove us NOW SetTouch( NULL ); SetThink( NULL ); PhysCallbackRemove( this->NetworkProp() ); return; } } m_bInAir = false; CollisionProp()->UseTriggerBounds( true, 24 ); g_PostSimulationQueue.QueueCall( this, &CBaseEntity::SetOwnerEntity, (CBaseEntity*)NULL ); // const CBaseEntity *host = te->GetSuppressHost(); // te->SetSuppressHost( NULL ); // StopParticleEffects( this ); // te->SetSuppressHost( (CBaseEntity*)host ); SetTouch( &CGETKnife::PickupTouch ); SetThink( &CGETKnife::RemoveThink ); g_PostSimulationQueue.QueueCall(this, &CBaseEntity::SetCollisionGroup, COLLISION_GROUP_DROPPEDWEAPON); SetNextThink( gpGlobals->curtime + 10.0f ); } }
void CGETKnife::DamageTouch( CBaseEntity *pOther ) { if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) return; if ( !PassServerEntityFilter( this, pOther) ) return; if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) ) return; if (!pOther->IsPlayer() && !pOther->IsNPC()) return; Vector vecAiming; VPhysicsGetObject()->GetVelocity( &vecAiming, NULL ); VectorNormalize( vecAiming ); trace_t tr; UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (vecAiming * 24), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); // We didn't hit the player again with our damage cast. Do a cast to the player's center to get a proper hit. if (tr.m_pEnt != pOther) { Vector TargetVec = pOther->GetAbsOrigin(); TargetVec.z = min(GetAbsOrigin().z, pOther->EyePosition().z); //Make sure we don't cast over their head. UTIL_TraceLine(GetAbsOrigin(), pOther->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); } // TEMPORARY DEBUGGING PURPOSES // DebugDrawLine( tr.startpos, tr.endpos, 0, 255, 0, true, 5.0f ); // debugoverlay->AddSweptBoxOverlay( tr.startpos, tr.endpos, CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), GetAbsAngles(), 0, 0, 255, 100, 5.0f ); // END TEMPORARY // If our target can take damage and the trace actually hit our target if ( pOther->m_takedamage != DAMAGE_NO && tr.fraction < 1.0f && tr.m_pEnt == pOther ) { ClearMultiDamage(); CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), GetDamage(), DMG_SLASH | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecAiming, tr.endpos, TKNIFE_FORCE_SCALE ); dmgInfo.SetDamagePosition( tr.endpos ); if ( this->GetOwnerEntity() && this->GetOwnerEntity()->IsPlayer() ) { CBasePlayer *pPlayer = ToBasePlayer( this->GetOwnerEntity() ); dmgInfo.SetWeapon( pPlayer->Weapon_OwnsThisType( "weapon_knife_throwing" ) ); } pOther->DispatchTraceAttack( dmgInfo, vecAiming, &tr ); ApplyMultiDamage(); SetAbsVelocity( vec3_origin ); SetTouch( NULL ); SetThink( NULL ); PhysCallbackRemove( this->NetworkProp() ); } }
//----------------------------------------------------------------------------- // Purpose: Handles all flight movement because we don't ever build paths when // when we are flying. // Input : flInterval - Seconds to simulate. //----------------------------------------------------------------------------- bool CNPC_Crow::OverrideMove( float flInterval ) { if ( GetNavigator()->GetPath()->CurWaypointNavType() == NAV_FLY && GetNavigator()->GetNavType() != NAV_FLY ) { SetNavType( NAV_FLY ); } if ( IsFlying() ) { if ( GetNavigator()->GetPath()->GetCurWaypoint() ) { if ( m_flLastStuckCheck <= gpGlobals->curtime ) { if ( m_vLastStoredOrigin == GetAbsOrigin() ) { if ( GetAbsVelocity() == vec3_origin ) { float flDamage = m_iHealth; CTakeDamageInfo dmgInfo( this, this, flDamage, DMG_GENERIC ); GuessDamageForce( &dmgInfo, vec3_origin - Vector( 0, 0, 0.1 ), GetAbsOrigin() ); TakeDamage( dmgInfo ); return false; } else { m_vLastStoredOrigin = GetAbsOrigin(); } } else { m_vLastStoredOrigin = GetAbsOrigin(); } m_flLastStuckCheck = gpGlobals->curtime + 1.0f; } if (m_bReachedMoveGoal ) { SetIdealActivity( (Activity)ACT_CROW_LAND ); SetFlyingState( FlyState_Landing ); TaskMovementComplete(); } else { SetIdealActivity ( ACT_FLY ); MoveCrowFly( flInterval ); } } else { SetSchedule( SCHED_CROW_IDLE_FLY ); SetFlyingState( FlyState_Flying ); SetIdealActivity ( ACT_FLY ); } return true; } return false; }
void CDODPlayer::FireBullets( const FireBulletsInfo_t &info ) { trace_t tr; trace_t reverseTr; //Used to find exit points static int iMaxPenetrations = 6; int iPenetrations = 0; float flDamage = info.m_iDamage; //Remaining damage in the bullet Vector vecSrc = info.m_vecSrc; Vector vecEnd = vecSrc + info.m_vecDirShooting * info.m_flDistance; static int iTraceMask = ( ( MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX | CONTENTS_PRONE_HELPER ) & ~CONTENTS_GRATE ); CBaseEntity *pLastHitEntity = this; // start with us so we don't trace ourselves int iDamageType = GetAmmoDef()->DamageType( info.m_iAmmoType ); int iCollisionGroup = COLLISION_GROUP_NONE; #ifdef GAME_DLL bool iNumHeadshots = 0; #endif while ( flDamage > 0 && iPenetrations < iMaxPenetrations ) { //DevMsg( 2, "penetration: %d, starting dmg: %.1f\n", iPenetrations, flDamage ); CBaseEntity *pPreviousHit = pLastHitEntity; // skip the shooter always CTraceFilterSkipTwoEntities ignoreShooterAndPrevious( this, pPreviousHit, iCollisionGroup ); UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &tr ); const float rayExtension = 40.0f; UTIL_ClipTraceToPlayers( vecSrc, vecEnd + info.m_vecDirShooting * rayExtension, iTraceMask, &ignoreShooterAndPrevious, &tr ); if ( tr.fraction == 1.0f ) break; // we didn't hit anything, stop tracing shoot // New hitbox code that uses hitbox groups instead of trying to trace // through the player if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { switch( tr.hitgroup ) { #ifdef GAME_DLL case HITGROUP_HEAD: { if ( tr.m_pEnt->GetTeamNumber() != GetTeamNumber() ) { iNumHeadshots++; } } break; #endif case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: { //DevMsg( 2, "Hit arms, tracing against alt hitboxes.. \n" ); CDODPlayer *pPlayer = ToDODPlayer( tr.m_pEnt ); // set hitbox set to "dod_no_arms" pPlayer->SetHitboxSet( 1 ); trace_t newTr; // re-fire the trace UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &newTr ); // if we hit the same player in the chest if ( tr.m_pEnt == newTr.m_pEnt ) { //DevMsg( 2, ".. and we hit the chest.\n" ); Assert( tr.hitgroup != newTr.hitgroup ); // If we hit this, hitbox sets are broken // use that damage instead tr = newTr; } // set hitboxes back to "dod" pPlayer->SetHitboxSet( 0 ); } break; default: break; } } pLastHitEntity = tr.m_pEnt; if ( sv_showimpacts.GetBool() ) { #ifdef CLIENT_DLL // draw red client impact markers debugoverlay->AddBoxOverlay( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255, 0, 0, 127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawClientHitboxes( 4, true ); } #else // draw blue server impact markers NDebugOverlay::Box( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), 0,0,255,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawServerHitboxes( 4, true ); } #endif } #ifdef CLIENT_DLL // See if the bullet ended up underwater + started out of the water if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) { trace_t waterTrace; UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, iCollisionGroup, &waterTrace ); if( waterTrace.allsolid != 1 ) { CEffectData data; data.m_vOrigin = waterTrace.endpos; data.m_vNormal = waterTrace.plane.normal; data.m_flScale = random->RandomFloat( 8, 12 ); if ( waterTrace.contents & CONTENTS_SLIME ) { data.m_fFlags |= FX_WATER_IN_SLIME; } DispatchEffect( "gunshotsplash", data ); } } else { //Do Regular hit effects // Don't decal nodraw surfaces if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = tr.m_pEnt; if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) ) { UTIL_ImpactTrace( &tr, iDamageType ); } } } #endif // Get surface where the bullet entered ( if it had different surfaces on enter and exit ) surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps ); Assert( pSurfaceData ); float flMaterialMod = GetDensityFromMaterial(pSurfaceData); if ( iDamageType & DMG_MACHINEGUN ) { flMaterialMod *= 0.65; } // try to penetrate object Vector penetrationEnd; float flMaxDistance = flDamage / flMaterialMod; #ifndef CLIENT_DLL ClearMultiDamage(); float flActualDamage = flDamage; CTakeDamageInfo dmgInfo( info.m_pAttacker, info.m_pAttacker, flActualDamage, iDamageType ); CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, info.m_vecDirShooting, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, info.m_vecDirShooting, &tr ); DevMsg( 2, "Giving damage ( %.1f ) to entity of type %s\n", flActualDamage, tr.m_pEnt->GetClassname() ); TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, info.m_vecDirShooting ); #endif int stepsize = 16; // displacement always stops the bullet if ( tr.IsDispSurface() ) { DevMsg( 2, "bullet was stopped by displacement\n" ); ApplyMultiDamage(); break; } // trace through the solid to find the exit point and how much material we went through if ( !TraceToExit( tr.endpos, info.m_vecDirShooting, penetrationEnd, stepsize, flMaxDistance ) ) { DevMsg( 2, "bullet was stopped\n" ); ApplyMultiDamage(); break; } // find exact penetration exit CTraceFilterSimple ignoreShooter( this, iCollisionGroup ); UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooter, &reverseTr ); // Now we can apply the damage, after we have traced the entity // so it doesn't break or die before we have a change to test against it #ifndef CLIENT_DLL ApplyMultiDamage(); #endif // Continue looking for the exit point if( reverseTr.m_pEnt != tr.m_pEnt && reverseTr.m_pEnt != NULL ) { // something was blocking, trace again CTraceFilterSkipTwoEntities ignoreShooterAndBlocker( this, reverseTr.m_pEnt, iCollisionGroup ); UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooterAndBlocker, &reverseTr ); } if ( sv_showimpacts.GetBool() ) { debugoverlay->AddLineOverlay( penetrationEnd, reverseTr.endpos, 255, 0, 0, true, 3.0 ); } // penetration was successful #ifdef CLIENT_DLL // bullet did penetrate object, exit Decal if ( !( reverseTr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = reverseTr.m_pEnt; if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) ) { UTIL_ImpactTrace( &reverseTr, iDamageType ); } } #endif //setup new start end parameters for successive trace // New start point is our last exit point vecSrc = reverseTr.endpos + /* 1.0 * */ info.m_vecDirShooting; // Reduce bullet damage by material and distanced travelled through that material // if it is < 0 we won't go through the loop again float flTraceDistance = VectorLength( reverseTr.endpos - tr.endpos ); flDamage -= flMaterialMod * flTraceDistance; if( flDamage > 0 ) { DevMsg( 2, "Completed penetration, new damage is %.1f\n", flDamage ); } else { DevMsg( 2, "bullet was stopped\n" ); } iPenetrations++; } #ifdef GAME_DLL HandleHeadshotAchievement( iNumHeadshots ); #endif }
void CASW_Flamer_Projectile::FlameHit( CBaseEntity *pOther, const Vector &vecHitPos, bool bOnlyHurtUnignited ) { if (!pOther) return; bool bHurt = true; if ( pOther->m_takedamage != DAMAGE_NO) { if ( pOther == m_pLastHitEnt ) return; if ( bOnlyHurtUnignited) { CBaseAnimating* pAnim = dynamic_cast<CBaseAnimating*>(pOther); if ( pAnim && pAnim->IsOnFire() ) { bHurt = false; } } if ( bHurt ) { Vector vecNormalizedVel = GetAbsVelocity(); ClearMultiDamage(); VectorNormalize( vecNormalizedVel ); if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() ) { CTakeDamageInfo dmgInfo( this, m_pGetsCreditedForDamage, m_flDamage, DMG_BURN ); dmgInfo.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, vecHitPos, asw_flamer_force.GetFloat() ); dmgInfo.SetDamagePosition( vecHitPos ); dmgInfo.SetWeapon( m_hCreatorWeapon.Get() ); pOther->TakeDamage(dmgInfo); } else { CTakeDamageInfo dmgInfo( this, m_pGetsCreditedForDamage, m_flDamage, DMG_BURN ); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, vecHitPos, asw_flamer_force.GetFloat() ); dmgInfo.SetDamagePosition( vecHitPos ); dmgInfo.SetWeapon( m_hCreatorWeapon.Get() ); pOther->TakeDamage(dmgInfo); } ApplyMultiDamage(); // keep going through normal entities? m_pLastHitEnt = pOther; } if ( pOther->Classify() == CLASS_ASW_SHIELDBUG ) // We also want to bounce off shield bugs { Vector vel = GetAbsVelocity(); Vector dir = vel; VectorNormalize( dir ); // reflect velocity around normal vel = -2.0f * dir + vel; vel *= 0.4f; // absorb 80% in impact SetAbsVelocity( vel ); } return; } if ( pOther->GetCollisionGroup() == ASW_COLLISION_GROUP_PASSABLE ) return; trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) ) { Vector vel = GetAbsVelocity(); if ( tr.startsolid ) { if ( !m_inSolid ) { // UNDONE: Do a better contact solution that uses relative velocity? vel *= -1.0f; // bounce backwards SetAbsVelocity(vel); } m_inSolid = true; return; } m_inSolid = false; if ( tr.DidHit() ) { Vector dir = vel; VectorNormalize(dir); // reflect velocity around normal vel = -2.0f * tr.plane.normal * DotProduct(vel,tr.plane.normal) + vel; vel *= 0.4f; // absorb 80% in impact //vel *= GRENADE_COEFFICIENT_OF_RESTITUTION; SetAbsVelocity( vel ); } return; } else { // Put a mark unless we've hit the sky if ( ( tr.surface.flags & SURF_SKY ) == false ) { UTIL_ImpactTrace( &tr, DMG_BURN ); } KillEffects(); UTIL_Remove( this ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CUnitBase::FireBullets( const FireBulletsInfo_t &info ) { VPROF_BUDGET( "CUnitBase::FireBullets", VPROF_BUDGETGROUP_UNITS ); static int tracerCount; trace_t tr; CAmmoDef* pAmmoDef = GetAmmoDef(); int nDamageType = pAmmoDef->DamageType(info.m_iAmmoType); //int nAmmoFlags = pAmmoDef->Flags(info.m_iAmmoType); int iNumShots; float flActualDamage; // the default attacker is ourselves CBaseEntity *pAttacker = info.m_pAttacker ? info.m_pAttacker : this; ClearMultiDamage(); g_MultiDamage.SetDamageType( nDamageType | DMG_NEVERGIB ); Vector vecDir; Vector vecEnd; // Adjust spread to accuracy Vector vecSpread( info.m_vecSpread ); //vecSpread.x = sin( ( (asin( info.m_vecSpread.x ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.y = sin( ( (asin( info.m_vecSpread.y ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.z = sin( ( (asin( info.m_vecSpread.z ) * 2.0f) * m_fAccuracy ) / 2.0f ); // Skip multiple entities when tracing CWarsBulletsFilter traceFilter( this, COLLISION_GROUP_NONE ); traceFilter.SetPassEntity( this ); // Standard pass entity for THIS so that it can be easily removed from the list after passing through a portal traceFilter.AddEntityToIgnore( info.m_pAdditionalIgnoreEnt ); CShotManipulator Manipulator( info.m_vecDirShooting ); iNumShots = info.m_iShots; flActualDamage = info.m_flDamage; if ( flActualDamage == 0.0 ) { flActualDamage = g_pGameRules->GetAmmoDamage( pAttacker, tr.m_pEnt, info.m_iAmmoType ); } flActualDamage *= m_fAccuracy; // Pretty much a damage modifier for (int iShot = 0; iShot < iNumShots; iShot++) { //vecDir = info.m_vecDirShooting; vecDir = Manipulator.ApplySpread( vecSpread ); vecEnd = info.m_vecSrc + vecDir * info.m_flDistance; AI_TraceLine(info.m_vecSrc, vecEnd, MASK_SHOT, &traceFilter, &tr); if( unit_debugfirebullets.GetBool() ) { #ifdef CLIENT_DLL NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 0, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 0, 255, 0.1f); #else NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 255, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 255, 255, 0.1f); #endif // CLIENT_DLL } // Make sure given a valid bullet type if (info.m_iAmmoType == -1) { DevMsg("ERROR: Undefined ammo type!\n"); return; } Vector vecTracerDest = tr.endpos; // do damage, paint decals if (tr.fraction != 1.0) { CTakeDamageInfo dmgInfo( pAttacker, pAttacker, flActualDamage, nDamageType ); CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, vecDir, tr.endpos ); dmgInfo.ScaleDamageForce( info.m_flDamageForceScale ); dmgInfo.SetAmmoType( info.m_iAmmoType ); (dynamic_cast<CBaseEntity *>(tr.m_pEnt))->DispatchTraceAttack( dmgInfo, vecDir, &tr ); // Effects only, FireBullets should be called on the client. // Dispatching on the server generates far too many events/data! #ifdef CLIENT_DLL DoImpactEffect( tr, nDamageType ); Vector vecTracerSrc = vec3_origin; ComputeTracerStartPosition( info.m_vecSrc, &vecTracerSrc ); trace_t Tracer; Tracer = tr; Tracer.endpos = vecTracerDest; MakeTracer( vecTracerSrc, Tracer, pAmmoDef->TracerType(info.m_iAmmoType) ); #endif // CLIENT_DLL } } #ifdef GAME_DLL ApplyMultiDamage(); #endif // GAME_DLL }
//----------------------------------------------------------------------------- // Purpose: // Input : *pOther - //----------------------------------------------------------------------------- void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) return; if ( pOther->m_takedamage != DAMAGE_NO ) { trace_t tr, tr2; tr = BaseClass::GetTouchTrace(); Vector vecNormalizedVel = GetAbsVelocity(); ClearMultiDamage(); VectorNormalize( vecNormalizedVel ); if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() ) { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_NEVERGIB ); dmgInfo.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } else { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } ApplyMultiDamage(); //Adrian: keep going through the glass. if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return; SetAbsVelocity( Vector( 0, 0, 0 ) ); // play body "thwack" sound EmitSound( "Weapon_Crossbow.BoltHitBody" ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 ); if ( tr2.fraction != 1.0f ) { // NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 ); // NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 ); if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) ) { CEffectData data; data.m_vOrigin = tr2.endpos; data.m_vNormal = vForward; data.m_nEntIndex = tr2.fraction != 1.0f; DispatchEffect( "BoltImpact", data ); } } SetTouch( NULL ); SetThink( NULL ); UTIL_Remove( this ); } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) ) { EmitSound( "Weapon_Crossbow.BoltHitWorld" ); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); float speed = VectorNormalize( vecDir ); // See if we should reflect off this surface float hitDot = DotProduct( tr.plane.normal, -vecDir ); if ( ( hitDot < 0.5f ) && ( speed > 100 ) ) { Vector vReflection = 2.0f * tr.plane.normal * hitDot + vecDir; QAngle reflectAngles; VectorAngles( vReflection, reflectAngles ); SetLocalAngles( reflectAngles ); SetAbsVelocity( vReflection * speed * 0.75f ); // Start to sink faster SetGravity( 1.0f ); } else { SetThink( &CCrossbowBolt::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); //FIXME: We actually want to stick (with hierarchy) to what we've hit SetMoveType( MOVETYPE_NONE ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; DispatchEffect( "BoltImpact", data ); UTIL_ImpactTrace( &tr, DMG_BULLET ); AddEffects( EF_NODRAW ); SetTouch( NULL ); SetThink( &CCrossbowBolt::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); if ( m_pGlowSprite != NULL ) { m_pGlowSprite->TurnOn(); m_pGlowSprite->FadeAndDie( 3.0f ); } } // Shoot some sparks if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER) { g_pEffects->Sparks( GetAbsOrigin() ); } } else { // Put a mark unless we've hit the sky if ( ( tr.surface.flags & SURF_SKY ) == false ) { UTIL_ImpactTrace( &tr, DMG_BULLET ); } UTIL_Remove( this ); } } if ( g_pGameRules->IsMultiplayer() ) { // SetThink( &CCrossbowBolt::ExplodeThink ); // SetNextThink( gpGlobals->curtime + 0.1f ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponGauss::Fire( void ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( pOwner == NULL ) return; m_bCharging = false; Vector startPos= pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecUp, vecRight; VectorVectors( aimDir, vecRight, vecUp ); float x, y, z; //Gassian spread do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); Vector endPos = startPos + ( aimDir * MAX_TRACE_LENGTH ); //Shoot a shot straight out trace_t tr; UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); #ifndef CLIENT_DLL ClearMultiDamage(); #endif CBaseEntity *pHit = tr.m_pEnt; #ifndef CLIENT_DLL CTakeDamageInfo dmgInfo( this, pOwner, sk_dmg_gauss.GetFloat(), DMG_SHOCK | DMG_BULLET ); #endif if ( pHit != NULL ) { #ifndef CLIENT_DLL CalculateBulletDamageForce( &dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos, 7.0f * 5.0f ); pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); #endif } if ( tr.DidHitWorld() ) { float hitAngle = -DotProduct( tr.plane.normal, aimDir ); if ( hitAngle < 0.5f ) { Vector vReflection; vReflection = 2.0 * tr.plane.normal * hitAngle + aimDir; startPos = tr.endpos; endPos = startPos + ( vReflection * MAX_TRACE_LENGTH ); //Draw beam to reflection point DrawBeam( tr.startpos, tr.endpos, 1.6, true ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); //Find new reflection end position UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt != NULL ) { #ifndef CLIENT_DLL dmgInfo.SetDamageForce( GetAmmoDef()->DamageForce(m_iPrimaryAmmoType) * vReflection ); dmgInfo.SetDamagePosition( tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, vReflection, &tr ); #endif } //Connect reflection point to end DrawBeam( tr.startpos, tr.endpos, 0.4 ); } else { DrawBeam( tr.startpos, tr.endpos, 1.6, true ); } } else { DrawBeam( tr.startpos, tr.endpos, 1.6, true ); } #ifndef CLIENT_DLL ApplyMultiDamage(); #endif UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f; AddViewKick(); return; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { if ( pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER) ) { // Some NPCs are triggers that can take damage (like antlion grubs). We should hit them. if ( ( pOther->m_takedamage == DAMAGE_NO ) || ( pOther->m_takedamage == DAMAGE_EVENTS_ONLY ) ) return; } if ( pOther->m_takedamage != DAMAGE_NO ) { trace_t tr, tr2; tr = BaseClass::GetTouchTrace(); Vector vecNormalizedVel = GetAbsVelocity(); ClearMultiDamage(); VectorNormalize( vecNormalizedVel ); #if defined(HL2_EPISODIC) //!!!HACKHACK - specific hack for ep2_outland_10 to allow crossbow bolts to pass through her bounding box when she's crouched in front of the player // (the player thinks they have clear line of sight because Alyx is crouching, but her BBOx is still full-height and blocks crossbow bolts. if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->Classify() == CLASS_PLAYER_ALLY_VITAL && FStrEq(STRING(gpGlobals->mapname), "ep2_outland_10") ) { // Change the owner to stop further collisions with Alyx. We do this by making her the owner. // The player won't get credit for this kill but at least the bolt won't magically disappear! SetOwnerEntity( pOther ); return; } #endif//HL2_EPISODIC if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() ) { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_crossbow.GetFloat(), DMG_NEVERGIB ); dmgInfo.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); CBasePlayer *pPlayer = ToBasePlayer( GetOwnerEntity() ); if ( pPlayer ) { gamestats->Event_WeaponHit( pPlayer, true, "weapon_crossbow", dmgInfo ); } } else { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_crossbow.GetFloat(), DMG_BULLET | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } ApplyMultiDamage(); //Adrian: keep going through the glass. if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return; /*if ( !pOther->IsAlive() ) { // We killed it! const surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps ); if ( pdata->game.material == CHAR_TEX_GLASS ) { return; } }*/ SetAbsVelocity( Vector( 0, 0, 0 ) ); // play body "thwack" sound EmitSound( "Weapon_Crossbow.BoltHitBody" ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_BLOCKLOS, pOther, COLLISION_GROUP_NONE, &tr2 ); if ( tr2.fraction != 1.0f ) { // NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 ); // NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 ); if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) ) { CEffectData data; data.m_vOrigin = tr2.endpos; data.m_vNormal = vForward; data.m_nEntIndex = tr2.fraction != 1.0f; DispatchEffect( "BoltImpact", data ); } } SetTouch( NULL ); SetThink( NULL ); if ( !g_pGameRules->IsMultiplayer() ) { UTIL_Remove( this ); } } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) ) { EmitSound( "Weapon_Crossbow.BoltHitWorld" ); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); float speed = VectorNormalize( vecDir ); // See if we should reflect off this surface float hitDot = DotProduct( tr.plane.normal, -vecDir ); if ( ( hitDot < 0.5f ) && ( speed > 100 ) ) { Vector vReflection = 2.0f * tr.plane.normal * hitDot + vecDir; QAngle reflectAngles; VectorAngles( vReflection, reflectAngles ); SetLocalAngles( reflectAngles ); SetAbsVelocity( vReflection * speed * 0.75f ); // Start to sink faster SetGravity( 1.0f ); } else { SetThink( &CCrossbowBolt::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); //FIXME: We actually want to stick (with hierarchy) to what we've hit SetMoveType( MOVETYPE_NONE ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; DispatchEffect( "BoltImpact", data ); UTIL_ImpactTrace( &tr, DMG_BULLET ); AddEffects( EF_NODRAW ); SetTouch( NULL ); SetThink( &CCrossbowBolt::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); if ( m_pGlowSprite != NULL ) { m_pGlowSprite->TurnOn(); m_pGlowSprite->FadeAndDie( 3.0f ); } } // Shoot some sparks if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER) { g_pEffects->Sparks( GetAbsOrigin() ); } } else { // Put a mark unless we've hit the sky if ( ( tr.surface.flags & SURF_SKY ) == false ) { UTIL_ImpactTrace( &tr, DMG_BULLET ); } UTIL_Remove( this ); } } if ( g_pGameRules->IsMultiplayer() ) { // SetThink( &CCrossbowBolt::ExplodeThink ); // SetNextThink( gpGlobals->curtime + 0.1f ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponGaussGun::ChargedFire() { if ( InGameRules()->IsMultiplayer() ) { } CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; bool penetrated = false; //Play shock sounds WeaponSound( SINGLE ); WeaponSound( SPECIAL2 ); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); StopChargeSound(); m_bCharging = false; m_bChargeIndicated = false; m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f; m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; //Shoot a shot straight out Vector startPos= pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector endPos = startPos + ( aimDir * MAX_TRACE_LENGTH ); trace_t tr; UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); #ifndef CLIENT_DLL ClearMultiDamage(); //Find how much damage to do float flChargeAmount = ( gpGlobals->curtime - m_flChargeStartTime ) / MAX_GAUSS_CHARGE_TIME; //Clamp this if ( flChargeAmount > 1.0f ) flChargeAmount = 1.0f; //Determine the damage amount float flDamage = sk_plr_dmg_gauss.GetFloat() + ( ( sk_plr_max_dmg_gauss.GetFloat() - sk_plr_dmg_gauss.GetFloat() ) * flChargeAmount ); #endif CBaseEntity *pHit = tr.m_pEnt; if ( tr.DidHitWorld() ) { //Try wall penetration UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); UTIL_DecalTrace( &tr, "RedGlowFade" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); Vector testPos = tr.endpos + ( aimDir * 48.0f ); UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid == false ) { UTIL_DecalTrace( &tr, "RedGlowFade" ); penetrated = true; } } #ifndef CLIENT_DLL else if ( pHit != NULL ) { CTakeDamageInfo dmgInfo( this, pOwner, flDamage, DMG_SHOCK | DMG_DISSOLVE ); CalculateBulletDamageForce( &dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos ); //Do direct damage to anything in our path pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); } ApplyMultiDamage(); #endif UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); QAngle viewPunch; viewPunch.x = random->RandomFloat( -4.0f, -8.0f ); viewPunch.y = random->RandomFloat( -0.25f, 0.25f ); viewPunch.z = 0; pOwner->ViewPunch( viewPunch ); DrawBeam( startPos, tr.endpos, 25, true ); #ifndef CLIENT_DLL Vector recoilForce = pOwner->BodyDirection2D() * -( flDamage * 10.0f ); recoilForce[2] += 300.0f;//128 pOwner->ApplyAbsVelocityImpulse( recoilForce ); #endif CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); #ifndef CLIENT_DLL if ( penetrated == true ) RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL ); // Register a muzzleflash for the AI pOwner->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASW_PropJeep::FireChargedCannon( void ) { bool penetrated = false; m_bCannonCharging = false; m_flCannonTime = gpGlobals->curtime + 0.5f; StopChargeSound(); CPASAttenuationFilter sndFilter( this, "PropJeep.FireChargedCannon" ); EmitSound( sndFilter, entindex(), "PropJeep.FireChargedCannon" ); //Find the direction the gun is pointing in Vector aimDir; GetCannonAim( &aimDir ); Vector endPos = m_vecGunOrigin + ( aimDir * MAX_TRACE_LENGTH ); //Shoot a shot straight out trace_t tr; UTIL_TraceLine( m_vecGunOrigin, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); ClearMultiDamage(); //Find how much damage to do float flChargeAmount = ( gpGlobals->curtime - m_flCannonChargeStartTime ) / MAX_GAUSS_CHARGE_TIME; //Clamp this if ( flChargeAmount > 1.0f ) { flChargeAmount = 1.0f; } //Determine the damage amount //FIXME: Use ConVars! float flDamage = 15 + ( ( 250 - 15 ) * flChargeAmount ); CBaseEntity *pHit = tr.m_pEnt; //Look for wall penetration if ( tr.DidHitWorld() && !(tr.surface.flags & SURF_SKY) ) { //Try wall penetration UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); UTIL_DecalTrace( &tr, "RedGlowFade" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); Vector testPos = tr.endpos + ( aimDir * 48.0f ); UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, GetDriver(), COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid == false ) { UTIL_DecalTrace( &tr, "RedGlowFade" ); penetrated = true; } } else if ( pHit != NULL ) { CTakeDamageInfo dmgInfo( this, GetDriver(), flDamage, DMG_SHOCK ); CalculateBulletDamageForce( &dmgInfo, GetAmmoDef()->Index("GaussEnergy"), aimDir, tr.endpos, 1.0f + flChargeAmount * 4.0f ); //Do direct damage to anything in our path pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); } ApplyMultiDamage(); //Kick up an effect if ( !(tr.surface.flags & SURF_SKY) ) { UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); //Do a gauss explosion CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); } //Show the effect DrawBeam( m_vecGunOrigin, tr.endpos, 9.6 ); // Register a muzzleflash for the AI if ( m_hPlayer ) { m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5f ); } //Rock the car IPhysicsObject *pObj = VPhysicsGetObject(); if ( pObj != NULL ) { Vector shoveDir = aimDir * -( flDamage * 500.0f ); pObj->ApplyForceOffset( shoveDir, m_vecGunOrigin ); } //Do radius damage if we didn't penetrate the wall if ( penetrated == true ) { RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL ); } }
//Called from PhysicsSimulate() or ReceiveMessage() bool CDHLProjectile::OnTouch( trace_t &touchtr, bool bDecalOnly /*= false*/, ITraceFilter* pTraceFilter /*= NULL*/ ) { //Direction Vector vecDir = touchtr.endpos - touchtr.startpos; if ( vecDir == vec3_origin ) //Sometimes endpos==startpos so we need to get dir from velocity instead { #ifdef CLIENT_DLL vecDir = GetLocalVelocity(); #else vecDir = m_vecCurVelocity; #endif VectorNormalize( vecDir ); } CBaseEntity* ent = touchtr.m_pEnt; if ( !ent ) return false; if ( touchtr.DidHit() ) { //Never collide with self, shooter, or other projectiles if ( ent == this || dynamic_cast<CDHLProjectile*>(ent) || ent == (CBaseEntity*)m_pShooter ) //|| ( (m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE) && (ent == m_pFiringWeapon) ) ) //Combat knife - don't collide with weapon ent return false; //Hack: Sometimes hits are registered prematurely (usually to the torso area) with no hitbox. Pretend nothing happened unless one is found. if ( ent->IsPlayer() && touchtr.hitgroup == 0 ) return false; //Check friendly fire if ( CheckFriendlyFire( ent ) ) { if ( !bDecalOnly ) { ClearMultiDamage(); //Do damage CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET ); if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) { //CalculateMeleeDamageForce( &dmgInfo, vecDir, touchtr.endpos, 0.01f ); Vector vecForce = vecDir; VectorNormalize( vecForce ); //vecForce *= 10.0f; //Ripped from C_ClientRagdoll::ImpactTrace dmgInfo.SetDamageForce( vecForce ); #ifndef CLIENT_DLL if ( IsOnFire() ) { CBaseAnimating* pBAnim = dynamic_cast<CBaseAnimating*>(ent); if ( pBAnim ) pBAnim->Ignite( 10.0f, false ); } #endif } else CalculateBulletDamageForce( &dmgInfo, m_iAmmoType, vecDir, touchtr.endpos, 1.0f ); dmgInfo.SetDamagePosition( touchtr.endpos ); ent->DispatchTraceAttack( dmgInfo, vecDir, &touchtr ); ApplyMultiDamage(); } #ifdef CLIENT_DLL if ( ent->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return false; //Decals and such if ( !( touchtr.surface.flags & SURF_SKY ) && !touchtr.allsolid ) { IPredictionSystem::SuppressEvents( false ); if ( (m_iType == DHL_PROJECTILE_TYPE_BULLET || m_iType == DHL_PROJECTILE_TYPE_PELLET) ) { UTIL_ImpactTrace( &touchtr, DMG_BULLET ); } if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) PlayImpactSound( touchtr.m_pEnt, touchtr, touchtr.endpos, touchtr.surface.surfaceProps ); IPredictionSystem::SuppressEvents( !prediction->IsFirstTimePredicted() ); } #endif } if ( pTraceFilter && m_iType != DHL_PROJECTILE_TYPE_COMBATKNIFE ) { PenetrationData_t nPenetrationData = DHLShared::TestPenetration( touchtr, m_pShooter, pTraceFilter, m_iTimesPenetrated, m_flDistanceTravelled, m_iAmmoType ); if ( nPenetrationData.m_bShouldPenetrate ) { m_flDistanceTravelled += GetLocalOrigin().DistTo( nPenetrationData.m_vecNewBulletPos ); MoveProjectileToPosition( nPenetrationData.m_vecNewBulletPos ); m_iTimesPenetrated++; return true; //Keep going - but don't do anything else in this frame of PhysicsSimulate() } } //We're done unless what we hit was breakable glass if ( ent->GetCollisionGroup() != COLLISION_GROUP_BREAKABLE_GLASS ) { #ifdef CLIENT_DLL m_bCollided = true; AddEffects( EF_NODRAW ); if ( m_pTrail ) //NULL pointer here sometimes somehow... m_pTrail->AddEffects( EF_NODRAW ); #else EntityMessageBegin( this ); WRITE_BYTE( MSG_NOTIFY_REMOVAL ); MessageEnd(); if ( touchtr.DidHitWorld() && m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE && !( touchtr.surface.flags & SURF_SKY ) ) { CBaseCombatWeapon* pKnifeEnt = assert_cast<CBaseCombatWeapon*>(CreateEntityByName( "weapon_combatknife" )); if ( pKnifeEnt ) { pKnifeEnt->AddSpawnFlags( SF_NORESPAWN ); //Needed for weapon spawn & VPhysics setup to work correctly pKnifeEnt->SetAbsOrigin( touchtr.endpos ); QAngle angles = vec3_angle; Vector vecKnifeDir = touchtr.startpos - touchtr.endpos; VectorAngles( vecKnifeDir, angles ); angles[PITCH] -= 15.0f; //Correct for the .mdl being offset a bit pKnifeEnt->SetLocalAngles( angles ); DispatchSpawn( pKnifeEnt ); //Spawns vphys object and sets it up, essentially a copy of CWeaponHL2MPBase::FallInit() pKnifeEnt->VPhysicsDestroyObject(); //Using SOLID_VPHYSICS instead of SOLID_BBOX (as ordinary weapons do) helps resolve some of the client side collision oddities Assert( pKnifeEnt->VPhysicsInitNormal( SOLID_VPHYSICS, FSOLID_NOT_STANDABLE | FSOLID_TRIGGER, true ) ); pKnifeEnt->SetPickupTouch(); //Sets up automagic removal after time IPhysicsObject* pKnifePhys = pKnifeEnt->VPhysicsGetObject(); if ( pKnifePhys ) { //Knives are solid to bullets...the only way to make them non-solid to bullets is to do SetSolid( SOLID_NONE ) or AddSolidFlags( FSOLID_NOT_SOLID ) //which breaks the +use pickup even with FSOLID_TRIGGER set. Let's just call it a feature :) pKnifePhys->EnableMotion( false ); pKnifePhys->EnableCollisions( false ); } if ( IsOnFire() ) pKnifeEnt->Ignite( 10.0f, false ); } } //SetThink( &CDHLProjectile::SUB_Remove ); //SetNextThink( gpGlobals->curtime + 0.1 ); //SUB_Remove(); //SetMoveType( MOVETYPE_NONE ); m_flRemoveAt = gpGlobals->curtime + 0.1f; //Give the notification message a head start so that the client will have time to react #endif } } return true; }