Exemplo n.º 1
0
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 );
}
Exemplo n.º 2
0
//-----------------------------------------------------------------------------
// 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;
}
Exemplo n.º 3
0
//-----------------------------------------------------------------------------
// 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 );
		}
	}
}
Exemplo n.º 4
0
//-----------------------------------------------------------------------------
// 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();
					}
				}
			}
		}
	}
}
Exemplo n.º 5
0
//-----------------------------------------------------------------------------
// 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;
	}
}
Exemplo n.º 6
0
//-----------------------------------------------------------------------------
// 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 );
				}
			}
		}
	}
}
Exemplo n.º 7
0
//-----------------------------------------------------------------------------
// 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;
}
Exemplo n.º 8
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 );
	}
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
//-----------------------------------------------------------------------------
// 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 );
}
Exemplo n.º 12
0
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 );
		}
	}
}
Exemplo n.º 14
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;
}