bool CAI_BaseHumanoid::OnMoveBlocked( AIMoveResult_t *pResult ) { if ( *pResult != AIMR_BLOCKED_NPC && GetNavigator()->GetBlockingEntity() && !GetNavigator()->GetBlockingEntity()->IsNPC() ) { CBaseEntity *pBlocker = GetNavigator()->GetBlockingEntity(); float massBonus = ( IsNavigationUrgent() ) ? 40.0 : 0; if ( pBlocker->GetMoveType() == MOVETYPE_VPHYSICS && pBlocker != GetGroundEntity() && !pBlocker->IsNavIgnored() && !dynamic_cast<CBasePropDoor *>(pBlocker) && pBlocker->VPhysicsGetObject() && pBlocker->VPhysicsGetObject()->IsMoveable() && ( pBlocker->VPhysicsGetObject()->GetMass() <= 35.0 + massBonus + 0.1 || ( pBlocker->VPhysicsGetObject()->GetMass() <= 50.0 + massBonus + 0.1 && IsSmall( pBlocker ) ) ) ) { DbgNavMsg1( this, "Setting ignore on object %s", pBlocker->GetDebugName() ); pBlocker->SetNavIgnore( 2.5 ); } #if 0 else { CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>( pBlocker ); if ( pProp && pProp->GetHealth() && pProp->GetExplosiveDamage() == 0.0 && GetActiveWeapon() && !GetActiveWeapon()->ClassMatches( "weapon_rpg" ) ) { Msg( "!\n" ); // Destroy! } } #endif } return BaseClass::OnMoveBlocked( pResult ); }
//----------------------------------------------------------------------------- // A standard filter to be applied to just about everything. //----------------------------------------------------------------------------- bool StandardFilterRules( IHandleEntity *pHandleEntity, int fContentsMask ) { CBaseEntity *pCollide = EntityFromEntityHandle( pHandleEntity ); // Static prop case... if ( !pCollide ) return true; SolidType_t solid = pCollide->GetSolid(); const model_t *pModel = pCollide->GetModel(); if ( ( modelinfo->GetModelType( pModel ) != mod_brush ) || (solid != SOLID_BSP && solid != SOLID_VPHYSICS) ) { if ( (fContentsMask & CONTENTS_MONSTER) == 0 ) return false; } // This code is used to cull out tests against see-thru entities if ( !(fContentsMask & CONTENTS_WINDOW) && pCollide->IsTransparent() ) return false; // FIXME: this is to skip BSP models that are entities that can be // potentially moved/deleted, similar to a monster but doors don't seem to // be flagged as monsters // FIXME: the FL_WORLDBRUSH looked promising, but it needs to be set on // everything that's actually a worldbrush and it currently isn't if ( !(fContentsMask & CONTENTS_MOVEABLE) && (pCollide->GetMoveType() == MOVETYPE_PUSH))// !(touch->flags & FL_WORLDBRUSH) ) return false; return true; }
//----------------------------------------------------------------------------- // Purpose: Input handler that converts our target to a physics object. //----------------------------------------------------------------------------- void CPhysConvert::InputConvertTarget( inputdata_t &inputdata ) { bool createAsleep = HasSpawnFlags(SF_CONVERT_ASLEEP); // Fire output m_OnConvert.FireOutput( inputdata.pActivator, this ); CBaseEntity *entlist[512]; CBaseEntity *pSwap = gEntList.FindEntityByName( NULL, m_swapModel, inputdata.pActivator ); CBaseEntity *pEntity = NULL; int count = 0; while ( (pEntity = gEntList.FindEntityByName( pEntity, m_target, inputdata.pActivator )) != NULL ) { entlist[count++] = pEntity; if ( count >= ARRAYSIZE(entlist) ) break; } // if we're swapping to model out, don't loop over more than one object // multiple objects with the same brush model will render, but the dynamic lights // and decals will be shared between the two instances... if ( pSwap && count > 0 ) { count = 1; } for ( int i = 0; i < count; i++ ) { pEntity = entlist[i]; // don't convert something that is already physics based if ( pEntity->GetMoveType() == MOVETYPE_VPHYSICS ) { Msg( "ERROR phys_convert %s ! Already MOVETYPE_VPHYSICS\n", STRING(pEntity->m_iClassname) ); continue; } UnlinkFromParent( pEntity ); if ( pSwap ) { // we can't reuse this physics object, so kill it pEntity->VPhysicsDestroyObject(); pEntity->SetModel( STRING(pSwap->GetModelName()) ); } CBaseEntity *pPhys = CreateSimplePhysicsObject( pEntity, createAsleep ); // created phys object, now move hierarchy over if ( pPhys ) { pPhys->SetName( pEntity->GetEntityName() ); TransferChildren( pEntity, pPhys ); pEntity->AddSolidFlags( FSOLID_NOT_SOLID ); pEntity->m_fEffects |= EF_NODRAW; UTIL_Relink( pEntity ); UTIL_Remove( pEntity ); } } }
//----------------------------------------------------------------------------- // Purpose: Check to see if we've got a linked harpoon, and see if we should constrain something //----------------------------------------------------------------------------- void CHarpoon::CheckLinkedHarpoon( void ) { if ( m_hLinkedHarpoon ) { CHarpoon *pPlayerHarpoon = NULL; CHarpoon *pNonMovingHarpoon = NULL; // Find out if either of us has impaled something if ( GetImpaledTarget() && m_hLinkedHarpoon->GetImpaledTarget() ) { // Only care about players for now. One of the targets must be a player. CBaseTFPlayer *pPlayer = NULL; CBaseEntity *pOtherTarget = NULL; if ( GetImpaledTarget()->IsPlayer() ) { pPlayer = (CBaseTFPlayer*)GetImpaledTarget(); pPlayerHarpoon = this; pNonMovingHarpoon = m_hLinkedHarpoon; } else if ( m_hLinkedHarpoon->GetImpaledTarget()->IsPlayer() ) { pPlayer = (CBaseTFPlayer*)m_hLinkedHarpoon->GetImpaledTarget(); pNonMovingHarpoon = this; pPlayerHarpoon = m_hLinkedHarpoon; } // Found a player? if ( pPlayer ) { pOtherTarget = pNonMovingHarpoon->GetImpaledTarget(); // For now, we have to be linked to a non-moving target. Eventually we could support linked moving targets. // pOtherTarget == NULL means the harpoon's buried in the world. if ( pOtherTarget->IsBSPModel() || pOtherTarget->GetMoveType() == MOVETYPE_NONE ) { // Add a little slack m_flConstrainLength = ( m_hLinkedHarpoon->GetAbsOrigin() - GetAbsOrigin() ).Length() + 150; pPlayer->ActivateMovementConstraint( NULL, pNonMovingHarpoon->GetAbsOrigin(), m_flConstrainLength, 150.0f, 0.1f ); // Square it for later checking m_flConstrainLength *= m_flConstrainLength; // Start checking the length pPlayerHarpoon->m_flConstrainLength = m_flConstrainLength; pPlayerHarpoon->SetThink( ConstrainThink ); pPlayerHarpoon->SetNextThink( gpGlobals->curtime + 0.1f ); // Make the rope taught, and prevent it resizing if ( m_hRope ) { m_hRope->m_RopeFlags &= ~ROPE_RESIZE; m_hRope->RecalculateLength(); } } } } } }
//----------------------------------------------------------------------------- // Handle view smoothing when going up or down stairs //----------------------------------------------------------------------------- void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin ) { CBaseEntity *pGroundEntity = GetGroundEntity(); float flCurrentPlayerZ = GetLocalOrigin().z; float flCurrentPlayerViewOffsetZ = GetViewOffset().z; // Smooth out stair step ups // NOTE: Don't want to do this when the ground entity is moving the player if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() && m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ ) { int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1; float steptime = gpGlobals->frametime; if (steptime < 0) { steptime = 0; } m_flOldPlayerZ += steptime * 150 * dir; const float stepSize = 18.0f; if ( dir > 0 ) { if (m_flOldPlayerZ > flCurrentPlayerZ) { m_flOldPlayerZ = flCurrentPlayerZ; } if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize) { m_flOldPlayerZ = flCurrentPlayerZ - stepSize; } } else { if (m_flOldPlayerZ < flCurrentPlayerZ) { m_flOldPlayerZ = flCurrentPlayerZ; } if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize) { m_flOldPlayerZ = flCurrentPlayerZ + stepSize; } } eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ; } else { m_flOldPlayerZ = flCurrentPlayerZ; m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysExplosion::Explode( CBaseEntity *pActivator ) { CBaseEntity *pEntity = NULL; float adjustedDamage, falloff, flDist; Vector vecSpot; falloff = 1.0 / 2.5; // iterate on all entities in the vicinity. // I've removed the traceline heuristic from phys explosions. SO right now they will // affect entities through walls. (sjb) // UNDONE: Try tracing world-only? while ((pEntity = FindEntity(pEntity, pActivator)) != NULL) { // UNDONE: Ask the object if it should get force if it's not MOVETYPE_VPHYSICS? if ( pEntity->m_takedamage != DAMAGE_NO && (pEntity->GetMoveType() == MOVETYPE_VPHYSICS || (pEntity->VPhysicsGetObject() && !pEntity->IsPlayer())) ) { vecSpot = pEntity->BodyTarget( GetAbsOrigin() ); // decrease damage for an ent that's farther from the bomb. flDist = ( GetAbsOrigin() - vecSpot ).Length(); if( m_radius == 0 || flDist <= m_radius ) { adjustedDamage = flDist * falloff; adjustedDamage = m_damage - adjustedDamage; if ( adjustedDamage < 0 ) { adjustedDamage = 0; } CTakeDamageInfo info( this, this, adjustedDamage, DMG_BLAST ); CalculateExplosiveDamageForce( &info, (vecSpot - GetAbsOrigin()), GetAbsOrigin() ); if ( HasSpawnFlags( SF_PHYSEXPLOSION_NODAMAGE ) ) { pEntity->VPhysicsTakeDamage( info ); } else { pEntity->TakeDamage( info ); } } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysMagnet::DoMagnetSuck( CBaseEntity *pOther ) { if ( !HasSpawnFlags( SF_MAGNET_SUCK ) ) return; if ( !m_bActive ) return; // Don't repeatedly suck if ( m_flNextSuckTime > gpGlobals->curtime ) return; // Look for physics objects underneath the magnet and suck them onto it Vector vecCheckPos, vecSuckPoint; VectorTransform( Vector(0,0,-96), EntityToWorldTransform(), vecCheckPos ); VectorTransform( Vector(0,0,-64), EntityToWorldTransform(), vecSuckPoint ); CBaseEntity *pEntities[20]; int iNumEntities = UTIL_EntitiesInSphere( pEntities, 20, vecCheckPos, 80.0, 0 ); for ( int i = 0; i < iNumEntities; i++ ) { CBaseEntity *pEntity = pEntities[i]; if ( !pEntity || pEntity == pOther ) continue; IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); if ( pPhys && pEntity->GetMoveType() == MOVETYPE_VPHYSICS && pPhys->GetMass() < 5000 ) { // Do we have line of sight to it? trace_t tr; UTIL_TraceLine( GetAbsOrigin(), pEntity->GetAbsOrigin(), MASK_SHOT, this, 0, &tr ); if ( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { // Pull it towards the magnet Vector vecVelocity = (vecSuckPoint - pEntity->GetAbsOrigin()); VectorNormalize(vecVelocity); vecVelocity *= 5 * pPhys->GetMass(); pPhys->AddVelocity( &vecVelocity, NULL ); } } } m_flNextSuckTime = gpGlobals->curtime + 2.0; }
//----------------------------------------------------------------------------- // Purpose: Give the harpoon a yank //----------------------------------------------------------------------------- void CWeaponHarpoon::YankHarpoon( void ) { CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() ); if ( !pPlayer ) return; #if !defined( CLIENT_DLL ) if ( m_bActiveHarpoon && m_hHarpoon.Get() ) { // If the harpoon's impaled something, pull it towards me CBaseEntity *pTarget = m_hHarpoon->GetImpaledTarget(); if ( pTarget ) { if ( !pTarget->IsBSPModel() && pTarget->GetMoveType() != MOVETYPE_NONE ) { // Bring him to me! EmitSound( "Harpoon.Yank" ); // Get a yank vector, and raise it a little to get them off the ground if they're on it Vector vecOverHere = ( pPlayer->GetAbsOrigin() - pTarget->GetAbsOrigin() ); VectorNormalize( vecOverHere ); if ( pTarget->GetFlags() & FL_ONGROUND ) { pTarget->SetGroundEntity( NULL ); vecOverHere.z = 0.5; } pTarget->ApplyAbsVelocityImpulse( vecOverHere * 500 ); PlayAttackAnimation( ACT_VM_HAULBACK ); } } m_hHarpoon->SetThink( SUB_Remove ); m_hHarpoon->SetNextThink( gpGlobals->curtime + 5.0 ); m_hHarpoon = NULL; m_bActiveHarpoon = false; } DetachRope(); #endif }
void CPhysMotor::Activate( void ) { BaseClass::Activate(); // This gets called after all objects spawn and after all objects restore if ( m_attachedObject == NULL ) { CBaseEntity *pAttach = gEntList.FindEntityByName( NULL, m_nameAttach, NULL ); if ( pAttach && pAttach->GetMoveType() == MOVETYPE_VPHYSICS ) { m_attachedObject = pAttach; IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); CalculateAcceleration(); matrix3x4_t matrix; pPhys->GetPositionMatrix( matrix ); Vector motorAxis_ls; VectorIRotate( m_motor.m_axis, matrix, motorAxis_ls ); float inertia = DotProductAbs( pPhys->GetInertia(), motorAxis_ls ); m_motor.m_maxTorque = inertia * m_motor.m_inertiaFactor * (m_angularAcceleration + m_additionalAcceleration); m_motor.m_restistanceDamping = 1.0f; } } if ( m_attachedObject ) { IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); // create a hinge constraint for this object? if ( m_spawnflags & SF_MOTOR_HINGE ) { // UNDONE: Don't do this on restore? if ( !m_pHinge ) { constraint_hingeparams_t hingeParams; hingeParams.Defaults(); hingeParams.worldAxisDirection = m_motor.m_axis; hingeParams.worldPosition = GetLocalOrigin(); m_pHinge = physenv->CreateHingeConstraint( g_PhysWorldObject, pPhys, NULL, hingeParams ); m_pHinge->SetGameData( (void *)this ); } if ( m_spawnflags & SF_MOTOR_NOCOLLIDE ) { physenv->DisableCollisions( pPhys, g_PhysWorldObject ); } } else { m_pHinge = NULL; } // NOTE: On restore, this path isn't run because m_pController will not be NULL if ( !m_pController ) { m_pController = physenv->CreateMotionController( &m_motor ); m_pController->AttachObject( m_attachedObject->VPhysicsGetObject() ); if ( m_spawnflags & SF_MOTOR_START_ON ) { TurnOn(); } } } // Need to do this on restore since there's no good way to save this if ( m_pController ) { m_pController->SetEventHandler( &m_motor ); } }
void CGEPropDynamic::Materialize(void) { //A more lightweight and optional func_rebreakable materalize function CreateVPhysics(); if (m_bRobustSpawn) { // iterate on all entities in the vicinity. CBaseEntity *pEntity; Vector max = CollisionProp()->OBBMaxs(); for (CEntitySphereQuery sphere(GetAbsOrigin(), max.NormalizeInPlace()); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity()) { if (pEntity == this || pEntity->GetSolid() == SOLID_NONE || pEntity->GetSolid() == SOLID_BSP || pEntity->GetSolidFlags() & FSOLID_NOT_SOLID || pEntity->GetMoveType() & MOVETYPE_NONE) continue; // Ignore props that can't move if (pEntity->VPhysicsGetObject() && !pEntity->VPhysicsGetObject()->IsMoveable()) continue; // Prevent respawn if we are blocked by anything and try again in 1 second if (Intersects(pEntity)) { SetSolid(SOLID_NONE); AddSolidFlags(FSOLID_NOT_SOLID); VPhysicsDestroyObject(); SetNextThink(gpGlobals->curtime + 1.0f); return; } } } m_iHealth = m_iHealthOverride; if (m_iHealth > 0) m_takedamage = DAMAGE_YES; RemoveEffects(EF_NODRAW); RemoveSolidFlags(FSOLID_NOT_SOLID); m_bUsingBrokenSkin = false; if (m_bUseRandomSkins) PickNewSkin(); else m_nSkin = m_iStartingSkin; SetRenderColor(m_col32basecolor.r, m_col32basecolor.g, m_col32basecolor.b); m_Respawn.FireOutput(this, this); }
//----------------------------------------------------------------------------- // Purpose: Spawn an instance of the entity //----------------------------------------------------------------------------- void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternateAngles ) { CPointTemplate *pTemplate = FindTemplate(); if (!pTemplate) return; // Spawn our template Vector vecSpawnOrigin = GetAbsOrigin(); QAngle vecSpawnAngles = GetAbsAngles(); if( vecAlternateOrigin != vec3_invalid ) { // We have a valid alternate origin and angles. Use those instead // of spawning the items at my own origin and angles. vecSpawnOrigin = vecAlternateOrigin; vecSpawnAngles = vecAlternateAngles; } CUtlVector<CBaseEntity*> hNewEntities; if ( !pTemplate->CreateInstance( vecSpawnOrigin, vecSpawnAngles, &hNewEntities, this ) ) return; //Adrian: oops we couldn't spawn the entity (or entities) for some reason! if ( hNewEntities.Count() == 0 ) return; m_hCurrentInstance = hNewEntities[0]; // Assume it'll block us m_hCurrentBlocker = m_hCurrentInstance; m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin(); // Store off the mins & maxs the first time we spawn if ( m_vecEntityMins == vec3_origin ) { m_hCurrentInstance->CollisionProp()->WorldSpaceAABB( &m_vecEntityMins, &m_vecEntityMaxs ); m_vecEntityMins -= m_hCurrentInstance->GetAbsOrigin(); m_vecEntityMaxs -= m_hCurrentInstance->GetAbsOrigin(); } // Fire our output m_pOutputOnSpawned.FireOutput( this, this ); // Start thinking if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN ) { SetThink( &CEnvEntityMaker::CheckSpawnThink ); SetNextThink( gpGlobals->curtime + 0.5f ); } // If we have a specified post spawn speed, apply it to all spawned entities if ( m_flPostSpawnSpeed ) { for ( int i = 0; i < hNewEntities.Count(); i++ ) { CBaseEntity *pEntity = hNewEntities[i]; if ( pEntity->GetMoveType() == MOVETYPE_NONE ) continue; // Calculate a velocity for this entity Vector vForward,vRight,vUp; QAngle angSpawnDir( m_angPostSpawnDirection ); if ( m_bPostSpawnUseAngles ) { if ( GetParent() ) { angSpawnDir += GetParent()->GetAbsAngles(); } else { angSpawnDir += GetAbsAngles(); } } AngleVectors( angSpawnDir, &vForward, &vRight, &vUp ); Vector vecShootDir = vForward; vecShootDir += vRight * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance; vecShootDir += vForward * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance; vecShootDir += vUp * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance; VectorNormalize( vecShootDir ); vecShootDir *= m_flPostSpawnSpeed; // Apply it to the entity IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); if ( pPhysicsObject ) { pPhysicsObject->AddVelocity(&vecShootDir, NULL); } else { pEntity->SetAbsVelocity( vecShootDir ); } } } pTemplate->CreationComplete( hNewEntities ); }
void CWeaponGravityGun::SecondaryAttack( void ) { m_flNextSecondaryAttack = gpGlobals->curtime + 0.1; if ( m_active ) { EffectDestroy(); SoundDestroy(); return; } CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); Assert( pOwner ); if ( pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0 ) return; m_viewModelIndex = pOwner->entindex(); // Make sure I've got a view model CBaseViewModel *vm = pOwner->GetViewModel(); if ( vm ) { m_viewModelIndex = vm->entindex(); } Vector forward; pOwner->EyeVectors( &forward ); Vector start = pOwner->Weapon_ShootPosition(); Vector end = start + forward * 4096; trace_t tr; UTIL_TraceLine( start, end, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0 || (tr.surface.flags & SURF_SKY) ) return; CBaseEntity *pHit = tr.m_pEnt; if ( pHit->entindex() == 0 ) { pHit = NULL; } else { // if the object has no physics object, or isn't a physprop or brush entity, then don't glue if ( !pHit->VPhysicsGetObject() || pHit->GetMoveType() != MOVETYPE_VPHYSICS ) return; } QAngle angles; WeaponSound( SINGLE ); pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType ); VectorAngles( tr.plane.normal, angles ); Vector endPoint = tr.endpos + tr.plane.normal; CGravityPellet *pPellet = (CGravityPellet *)CBaseEntity::Create( "gravity_pellet", endPoint, angles, this ); if ( pHit ) { pPellet->SetParent( pHit ); } AddPellet( pPellet, pHit, tr.plane.normal ); // UNDONE: Probably should just do this client side CBaseEntity *pEnt = GetBeamEntity(); CBeam *pBeam = CBeam::BeamCreate( PHYSGUN_BEAM_SPRITE, 1.5 ); pBeam->PointEntInit( endPoint, pEnt ); pBeam->SetEndAttachment( 1 ); pBeam->SetBrightness( 255 ); pBeam->SetColor( 255, 0, 0 ); pBeam->RelinkBeam(); pBeam->LiveForTime( 0.1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseHelicopter::DoRotorPhysicsPush( const Vector &vecRotorOrigin, float flAltitude ) { CBaseEntity *pEntity = NULL; trace_t tr; // First, trace down and find out where the was is hitting the ground UTIL_TraceLine( vecRotorOrigin, vecRotorOrigin+Vector(0,0,-flAltitude), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER), NULL, COLLISION_GROUP_NONE, &tr ); // Always raise the physics origin a bit Vector vecPhysicsOrigin = tr.endpos + Vector(0,0,64); // Debug if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH ) { NDebugOverlay::Cross3D( vecPhysicsOrigin, -Vector(16,16,16), Vector(16,16,16), 0, 255, 255, true, 0.1f ); } // Push entities that we've pushed before, and are still within range // Walk backwards because they may be removed if they're now out of range int iCount = m_hEntitiesPushedByWash.Count(); bool bWasPushingObjects = (iCount > 0); for ( int i = (iCount-1); i >= 0; i-- ) { if ( !DoWashPush( &(m_hEntitiesPushedByWash[i]), vecPhysicsOrigin ) ) { // Out of range now, so remove m_hEntitiesPushedByWash.Remove(i); } } if ( m_flRotorWashEntitySearchTime > gpGlobals->curtime ) return; // Any spare slots? iCount = m_hEntitiesPushedByWash.Count(); if ( iCount >= BASECHOPPER_WASH_MAX_OBJECTS ) return; // Find the lightest physics entity below us and add it to our list to push around CBaseEntity *pLightestEntity = NULL; float flLightestMass = 9999; while ((pEntity = gEntList.FindEntityInSphere(pEntity, vecPhysicsOrigin, BASECHOPPER_WASH_RADIUS )) != NULL) { IRotorWashShooter *pShooter = GetRotorWashShooter( pEntity ); if ( pEntity->IsEFlagSet( EFL_NO_ROTORWASH_PUSH )) continue; if ( pShooter || pEntity->GetMoveType() == MOVETYPE_VPHYSICS || (pEntity->VPhysicsGetObject() && !pEntity->IsPlayer()) ) { // Make sure it's not already in our wash bool bAlreadyPushing = false; for ( int i = 0; i < iCount; i++ ) { if ( m_hEntitiesPushedByWash[i].hEntity == pEntity ) { bAlreadyPushing = true; break; } } if ( bAlreadyPushing ) continue; float flMass = FLT_MAX; if ( pShooter ) { flMass = 1.0f; } else { // Don't try to push anything too big IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); if ( pPhysObject ) { flMass = pPhysObject->GetMass(); if ( flMass > BASECHOPPER_WASH_MAX_MASS ) continue; } } // Ignore anything bigger than the one we've already found if ( flMass > flLightestMass ) continue; Vector vecSpot = pEntity->BodyTarget( vecPhysicsOrigin ); // Don't push things too far below our starting point (helps reduce through-roof cases w/o doing a trace) if ( fabs( vecSpot.z - vecPhysicsOrigin.z ) > 96 ) continue; Vector vecToSpot = ( vecSpot - vecPhysicsOrigin ); vecToSpot.z = 0; float flDist = VectorNormalize( vecToSpot ); if ( flDist > BASECHOPPER_WASH_RADIUS ) continue; // Try to cast to the helicopter; if we can't, then we can't be hit. if ( pEntity->GetServerVehicle() ) { UTIL_TraceLine( vecSpot, vecPhysicsOrigin, MASK_SOLID_BRUSHONLY, pEntity, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0f ) continue; } flLightestMass = flMass; pLightestEntity = pEntity; washentity_t Wash; Wash.hEntity = pLightestEntity; Wash.flWashStartTime = gpGlobals->curtime; m_hEntitiesPushedByWash.AddToTail( Wash ); // Can we fit more after adding this one? No? Then we are done. iCount = m_hEntitiesPushedByWash.Count(); if ( iCount >= BASECHOPPER_WASH_MAX_OBJECTS ) break; } } // Handle sound. // If we just started pushing objects, ramp the blast sound up. if ( !bWasPushingObjects && m_hEntitiesPushedByWash.Count() ) { if ( m_pRotorBlast ) { CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pRotorBlast, 1.0, 1.0 ); } } else if ( bWasPushingObjects && m_hEntitiesPushedByWash.Count() == 0 ) { if ( m_pRotorBlast ) { // We just stopped pushing objects, so fade the blast sound out. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pRotorBlast, 0, 1.0 ); } } }
Vector CASW_Simple_Alien::CalcDeathForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if ( info.GetDamageForce() != vec3_origin || (g_pGameRules->Damage_NoPhysicsForce(info.GetDamageType()))) { if( info.GetDamageType() & DMG_BLAST ) { float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; } return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CBaseHL2MPBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); //Do view kick // AddViewKick(); CBaseEntity *pHitEntity = traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); #ifndef CLIENT_DLL CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); if( pPlayer && pHitEntity->IsNPC() ) { // If bonking an NPC, adjust damage. info.AdjustPlayerDamageInflictedForSkillLevel(); } //BB: don't damage imortals if (pPlayer && pHitEntity->IsPlayer()) { if (((CHL2MP_Player *)pHitEntity)->KO) { info.SetDamage(0.0f); } } //BB: check for server doll, this means it is a STAKE hit, apply the damage to the player. if (pPlayer && pHitEntity->IsServerdoll()) { //we have hit a ragdoll... see if it has an alive player if (((CRagdollProp *)pHitEntity)->myBody != NULL && ((CRagdollProp *)pHitEntity)->team == COVEN_TEAMID_VAMPIRES) { //kill the player CTakeDamageInfo newinfo = info; newinfo.SetDamage(999.0f); ((CRagdollProp *)pHitEntity)->myBody->OnTakeDamage( newinfo ); } } 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 ); #endif //BB: fix this so that we have two distinct sounds if (pHitEntity->IsPlayer() || pHitEntity->IsNPC()) WeaponSound( MELEE_HIT ); else if (pHitEntity->GetMoveType() != MOVETYPE_NONE) WeaponSound( SPECIAL1 ); else WeaponSound( MELEE_HIT_WORLD ); } // Apply an impact effect ImpactEffect( traceHit ); }
//========================================================= // SonicAttack //========================================================= void CNPC_Houndeye::SonicAttack ( void ) { EmitSound( "NPC_Houndeye.SonicAttack" ); float flAdjustedDamage; float flDist; CBroadcastRecipientFilter filter2; te->BeamRingPoint(filter2, 0.0, GetAbsOrigin(), //origin 16, //start radius HOUNDEYE_MAX_ATTACK_RADIUS,//end radius m_iSpriteTexture, //texture 0, //halo index 0, //start frame 0, //framerate 0.2, //life 24, //width 16, //spread 0, //amplitude 188, //r 220, //g 255, //b 192, //a 0 //speed ); CBroadcastRecipientFilter filter3; te->BeamRingPoint(filter3, 0.0, GetAbsOrigin(), //origin 16, //start radius HOUNDEYE_MAX_ATTACK_RADIUS / 2, //end radius m_iSpriteTexture, //texture 0, //halo index 0, //start frame 0, //framerate 0.2, //life 24, //width 16, //spread 0, //amplitude 188, //r 220, //g 255, //b 192, //a 0 //speed ); CBaseEntity *pEntity = NULL; // iterate on all entities in the vicinity. while ((pEntity = gEntList.FindEntityInSphere(pEntity, GetAbsOrigin(), HOUNDEYE_MAX_ATTACK_RADIUS)) != NULL) { if (pEntity->m_takedamage != DAMAGE_NO) { if (!FClassnameIs(pEntity, "npc_houndeye")) {// houndeyes don't hurt other houndeyes with their attack // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. // This means that you must get out of the houndeye's attack range entirely to avoid damage. // Calculate full damage first flAdjustedDamage = sk_Houndeye_dmg_blast.GetFloat(); flDist = (pEntity->WorldSpaceCenter() - GetAbsOrigin()).Length(); flAdjustedDamage -= (flDist / HOUNDEYE_MAX_ATTACK_RADIUS) * flAdjustedDamage; if (!FVisible(pEntity)) { if (pEntity->IsPlayer()) { // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients // so that monsters in other parts of the level don't take the damage and get pissed. flAdjustedDamage *= 0.5; } else if (!FClassnameIs(pEntity, "func_breakable") && !FClassnameIs(pEntity, "func_pushable")) { // do not hurt nonclients through walls, but allow damage to be done to breakables flAdjustedDamage = 0; } } //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); if (flAdjustedDamage > 0) { CTakeDamageInfo info(this, this, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB); CalculateExplosiveDamageForce(&info, (pEntity->GetAbsOrigin() - GetAbsOrigin()), pEntity->GetAbsOrigin()); pEntity->TakeDamage(info); if ((pEntity->GetAbsOrigin() - GetAbsOrigin()).Length2D() <= HOUNDEYE_MAX_ATTACK_RADIUS) { if (pEntity->GetMoveType() == MOVETYPE_VPHYSICS || (pEntity->VPhysicsGetObject() && !pEntity->IsPlayer())) { IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); if (pPhysObject) { float flMass = pPhysObject->GetMass(); if (flMass <= HOUNDEYE_TOP_MASS) { // Increase the vertical lift of the force Vector vecForce = info.GetDamageForce(); vecForce.z *= 2.0f; info.SetDamageForce(vecForce); pEntity->VPhysicsTakeDamage(info); } } } } } } } } }
Vector QUA_helicopter::CalcDamageForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if (info.GetDamageForce() != vec3_origin || (info.GetDamageType() & /*DMG_NO_PHYSICS_FORCE*/DMG_BLAST)) { //if( info.GetDamageType() & DMG_BLAST ) //{ // Fudge blast forces a little bit, so that each // victim gets a slightly different trajectory. // This simulates features that usually vary from // person-to-person variables such as bodyweight, // which are all indentical for characters using the same model. float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; //} return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }