//-----------------------------------------------------------------------------
// Purpose: Called when an entity starts touching us.
// Input  : pOther - The entity that is touching us.
//-----------------------------------------------------------------------------
void CTriggerPortalCleanser::StartTouch( CBaseEntity *pOther )
{
	if ( PassesTriggerFilters(pOther) )
	{
		EHANDLE hOther;
		hOther = pOther;
		
		bool bAdded = false;
		if ( m_hTouchingEntities.Find( hOther ) == m_hTouchingEntities.InvalidIndex() )
		{
			m_hTouchingEntities.AddToTail( hOther );
			bAdded = true;
		}

		m_OnStartTouch.FireOutput(pOther, this);

		if ( bAdded && ( m_hTouchingEntities.Count() == 1 ) )
		{
			// First entity to touch us that passes our filters
			m_OnStartTouchAll.FireOutput( pOther, this );
		}

		if ( portal_cleanser_debug.GetBool() )
		{
			Msg("%s START-TOUCH: for %s\n", GetDebugName(), pOther->GetDebugName() );
		}

		if ( !pOther->IsPlayer() )
		{
			CBaseAnimating *pAnim = pOther->GetBaseAnimating();
			if ( !pAnim )
				return;

			// Can't dissolve twice.
			if ( pAnim->IsDissolving() )
				return;

			// Force player to drop this object.
			Pickup_ForcePlayerToDropThisObject( pOther );

			if ( !FClassnameIs( pOther, "prop_physics" ) )
			{
				if ( FClassnameIs( pOther, "simple_physics_prop" ) || FClassnameIs( pOther, "simple_physics_brush" ) )
				{
					// simple_physics_prop ?
					return;
				}

				if ( portal_cleanser_debug.GetBool() )
				{
					Msg("%s IS CREATING: simple_physics_prop\n", GetDebugName());
				}
				// Other object needs to be replaced by simple_physics_prop.
				pOther = CreateSimplePhysicsObject( pOther );

				// Dissolve the entity.
				CBaseAnimating *pAnim = pOther->GetBaseAnimating();
				pAnim->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );

				if ( portal_cleanser_debug.GetBool() )
				{
					Msg("%s DISSOLVE SIMPLE PHYSICS: %s\n", GetDebugName(), pOther->GetDebugName() );
				}

				// Outputs
				m_hActivator = pOther;
				m_OnDissolve.FireOutput(m_hActivator, this);

				return;
			}

			IPhysicsObject *pPhysics = pOther->VPhysicsGetObject();
			if ( pPhysics )
			{
				// Dissolve the entity.
				pAnim->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );

				if ( portal_cleanser_debug.GetBool() )
				{
					Msg("%s DISSOLVE PHYSICS: %s\n", GetDebugName(), pOther->GetDebugName() );
				}

				// Turn off the gravity for this object.
				pPhysics->EnableGravity( false );

				// Slow down and push up the object.
				Vector vecVelocity, vecAngular;
				pPhysics->GetVelocity( &vecVelocity, &vecAngular );
				vecVelocity /= 2;
				vecAngular /= 2;
				vecVelocity.z += 10;
				pPhysics->SetVelocity( &vecVelocity, &vecAngular );

				// Outputs
				m_hActivator = pOther;
				m_OnDissolve.FireOutput(m_hActivator, this);

				const char *pModelName = STRING( pOther->GetModelName() );
				if ( Q_strstr( pModelName, "models/props/metal_box.mdl" ) )
				{
					m_OnDissolveBox.FireOutput(m_hActivator, this);
				}
			}
		}
	}
}
Ejemplo n.º 2
0
//=========================================================
// GetIdealState - Overridden for Bullsquid to deal with
// the feature that makes it lose interest in headcrabs for
// a while if something injures it.
//=========================================================
MONSTERSTATE CBullsquid :: GetIdealState ( void )
{
	int	iConditions;

	iConditions = IScheduleFlags();

	// If no schedule conditions, the new ideal state is probably the reason we're in here.
	switch ( m_MonsterState )
	{
	case MONSTERSTATE_COMBAT:
		/*
		COMBAT goes to ALERT upon death of enemy
		*/
		{
			if ( m_hEnemy != NULL && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) )
			{
				// if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while.
				m_hEnemy = NULL;
				m_IdealMonsterState = MONSTERSTATE_ALERT;
			}
			break;
		}
	}

	m_IdealMonsterState = CBaseMonster :: GetIdealState();

	return m_IdealMonsterState;
}
//=========================================================
// GetIdealState - Overridden for Bullsquid to deal with
// the feature that makes it lose interest in headcrabs for 
// a while if something injures it. 
//=========================================================
NPC_STATE CNPC_Bullsquid::SelectIdealState( void )
{
	// If no schedule conditions, the new ideal state is probably the reason we're in here.
	switch ( m_NPCState )
	{
		case NPC_STATE_COMBAT:
		{
			// COMBAT goes to ALERT upon death of enemy
			if ( GetEnemy() != NULL && ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) ) && FClassnameIs( GetEnemy(), "monster_headcrab" ) )
			{
				// if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while.
				SetEnemy( NULL );
				return NPC_STATE_ALERT;
			}
			break;
		}
	}

	return BaseClass::SelectIdealState();
}
Ejemplo n.º 4
0
/* <18b4aa> ../cstrike/dlls/training_gamerules.cpp:52 */
void CHalfLifeTraining::__MAKE_VHOOK(PlayerThink)(CBasePlayer *pPlayer)
{
	if (pPlayer->pev->radsuit_finished && gpGlobals->time > pPlayer->pev->radsuit_finished)
	{
		SERVER_COMMAND("reload\n");
	}

	if (!pPlayer->m_iAccount)
	{
		if (pPlayer->pev->scale)
		{
			pPlayer->m_iAccount = (int)pPlayer->pev->scale;
		}
	}

	if (pPlayer->m_iTeam == UNASSIGNED)
	{
		pPlayer->SetProgressBarTime(0);
		pPlayer->m_bHasDefuser = pPlayer->pev->ideal_yaw != 0;
	}

	m_iHostagesRescued = 0;
	m_iRoundTimeSecs = (int)(gpGlobals->time + 1.0f);
	m_bFreezePeriod = FALSE;
	g_fGameOver = FALSE;

	pPlayer->m_iTeam = CT;
	pPlayer->m_bCanShoot = true;
	pPlayer->m_fLastMovement = gpGlobals->time;

	if (pPlayer->m_pActiveItem)
		pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS;
	else
		pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS;

	if (pPlayer->HasNamedPlayerItem("weapon_c4"))
	{
		if (pPlayer->m_rgAmmo[ pPlayer->GetAmmoIndex("C4") ] <= 0)
		{
			pPlayer->m_bHasC4 = false;

			CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon *)pPlayer->m_pActiveItem;

			if (FClassnameIs(pWeapon->pev, "weapon_c4"))
			{
				pPlayer->pev->weapons &= ~(1 << pWeapon->m_iId);
				pPlayer->RemovePlayerItem(pWeapon);
				pWeapon->Drop();
			}
		}
		else
			pPlayer->m_bHasC4 = true;
	}

	if (!pPlayer->m_bVGUIMenus)
	{
		if (fVGUIMenus)
		{
			pPlayer->m_bVGUIMenus = fVGUIMenus;
		}
	}

	CGrenade *pBomb = NULL;
	while ((pBomb = (CGrenade *)UTIL_FindEntityByClassname(pBomb, "grenade")) != NULL)
	{
		if (pBomb->m_pentCurBombTarget != NULL)
			pBomb->m_bStartDefuse = true;
	}

	if (pPlayer->m_signals.GetState() & SIGNAL_BUY)
	{
		if (!fInBuyArea)
		{
			FillAccountTime = 1;

			if (!fVisitedBuyArea)
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pPlayer->pev);
					WRITE_BYTE(STATUSICON_FLASH);
					WRITE_STRING("buyzone");
					WRITE_BYTE(0);
					WRITE_BYTE(160);
					WRITE_BYTE(0);
				MESSAGE_END();
			}
		}

		fInBuyArea = TRUE;

		if (pPlayer->m_iAccount < 16000 && FillAccountTime == 0.0f)
			FillAccountTime = gpGlobals->time + 5;

		if (FillAccountTime != 0.0f && gpGlobals->time > FillAccountTime)
		{
			if (!fVisitedBuyArea)
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgBlinkAcct, NULL, pPlayer->pev);
					WRITE_BYTE(3);
				MESSAGE_END();

				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pPlayer->pev);
					WRITE_BYTE(STATUSICON_SHOW);
					WRITE_STRING("buyzone");
					WRITE_BYTE(0);
					WRITE_BYTE(160);
					WRITE_BYTE(0);
				MESSAGE_END();

				fVisitedBuyArea = TRUE;
			}

			pPlayer->AddAccount(16000 - pPlayer->m_iAccount);
			FillAccountTime = 0;
		}
	}
	else if (fInBuyArea && fVisitedBuyArea)
	{
		fInBuyArea = FALSE;
	}

	pPlayer->pev->scale = pPlayer->m_iAccount;
	pPlayer->pev->ideal_yaw = pPlayer->m_bHasDefuser;

	if (TheBots != NULL)
	{
		TheBots->OnEvent(EVENT_PLAYER_CHANGED_TEAM, pPlayer);
	}
}
void CBaseDoor::Blocked( CBaseEntity *pOther )
{
	CBaseEntity	*pTarget	= NULL;
	CBaseDoor	*pDoor		= NULL;

//	ALERT(at_debug, "%s blocked\n", STRING(pev->targetname));

	// Hurt the blocker a little.
	if ( pev->dmg )
		if (m_hActivator)
			pOther->TakeDamage( pev, m_hActivator->pev, pev->dmg, DMG_CRUSH );	//AJH Attribute damage to he who switched me.
		else
			pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH );

	// if a door has a negative wait, it would never come back if blocked,
	// so let it just squash the object to death real fast

	if (m_flWait >= 0)
	{
		//LRC - thanks to [insert name here] for this
		if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
			STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) );
		if (m_toggle_state == TS_GOING_DOWN)
		{
			DoorGoUp();
		}
		else
		{
			DoorGoDown();
		}
	}

	// Block all door pieces with the same targetname here.
	//LRC - in immediate mode don't do this, doors are expected to do it themselves.
	if ( !m_iImmediateMode && !FStringNull ( pev->targetname ) )
	{
		for (;;)
		{
			pTarget = UTIL_FindEntityByTargetname(pTarget, STRING(pev->targetname));

			if ( !pTarget )
				break;

			if ( VARS( pTarget->pev ) != pev && FClassnameIs ( pTarget->pev, "func_door" ) ||
						FClassnameIs ( pTarget->pev, "func_door_rotating" ) )
			{
				pDoor = GetClassPtr( (CBaseDoor *) VARS(pTarget->pev) );
				if ( pDoor->m_flWait >= 0)
				{
					// avelocity == velocity!? LRC
					if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity)
					{
						// this is the most hacked, evil, bastardized thing I've ever seen. kjb
						if ( FClassnameIs ( pTarget->pev, "func_door" ) )
						{// set origin to realign normal doors
							pDoor->pev->origin = pev->origin;
							UTIL_SetVelocity(pDoor, g_vecZero);// stop!
						}
						else
						{// set angles to realign rotating doors
							pDoor->pev->angles = pev->angles;
							UTIL_SetAvelocity(pDoor, g_vecZero);
						}
					}
					if ( pDoor->m_toggle_state == TS_GOING_DOWN)
						pDoor->DoorGoUp();
					else
						pDoor->DoorGoDown();
				}
			}
		}
	}
}
Ejemplo n.º 6
0
void AvoidPushawayProps( CBaseCombatCharacter *pPlayer, CUserCmd *pCmd )
{
	// Figure out what direction we're moving and the extents of the box we're going to sweep 
	// against physics objects.
	Vector currentdir;
	Vector rightdir;
	AngleVectors( pCmd->viewangles, &currentdir, &rightdir, NULL );

	CBaseEntity *props[512];
#ifdef CLIENT_DLL
	int nEnts = GetPushawayEnts( pPlayer, props, ARRAYSIZE( props ), 0.0f, PARTITION_CLIENT_SOLID_EDICTS, NULL );
#else
	int nEnts = GetPushawayEnts( pPlayer, props, ARRAYSIZE( props ), 0.0f, PARTITION_ENGINE_SOLID_EDICTS, NULL );
#endif

	const Vector & ourCenter = pPlayer->WorldSpaceCenter();
	Vector nearestPropPoint;
	Vector nearestPlayerPoint;

	for ( int i=0; i < nEnts; i++ )
	{
		// Don't respond to this entity on the client unless it has PHYSICS_MULTIPLAYER_FULL set.
		IMultiplayerPhysics *pInterface = dynamic_cast<IMultiplayerPhysics*>( props[i] );
		if ( pInterface && pInterface->GetMultiplayerPhysicsMode() != PHYSICS_MULTIPLAYER_SOLID )
			continue;

		const float minMass = 10.0f; // minimum mass that can push a player back
		const float maxMass = 30.0f; // cap at a decently large value
		float mass = maxMass;
		if ( pInterface )
		{
			mass = pInterface->GetMass();
		}
		mass = clamp( mass, minMass, maxMass );
		
		mass = max( mass, 0 );
		mass /= maxMass; // bring into a 0..1 range

		// Push away from the collision point. The closer our center is to the collision point,
		// the harder we push away.
		props[i]->CollisionProp()->CalcNearestPoint( ourCenter, &nearestPropPoint );
		pPlayer->CollisionProp()->CalcNearestPoint( nearestPropPoint, &nearestPlayerPoint );
		Vector vPushAway = (nearestPlayerPoint - nearestPropPoint);
		float flDist = VectorNormalize( vPushAway );

		const float MaxPushawayDistance = 5.0f;
		if ( flDist > MaxPushawayDistance && !pPlayer->CollisionProp()->IsPointInBounds( nearestPropPoint ) )
		{
			continue;
		}

		// If we're not pushing, try from our center to the nearest edge of the prop
		if ( vPushAway.IsZero() )
		{
			vPushAway = (ourCenter - nearestPropPoint);
			flDist = VectorNormalize( vPushAway );
		}

		// If we're still not pushing, try from our center to the center of the prop
		if ( vPushAway.IsZero() )
		{
			vPushAway = (ourCenter - props[i]->WorldSpaceCenter());
			flDist = VectorNormalize( vPushAway );
		}

		flDist = max( flDist, 1 );

		float flForce = sv_pushaway_player_force.GetFloat() / flDist * mass;
		flForce = min( flForce, sv_pushaway_max_player_force.GetFloat() );

#ifndef CLIENT_DLL
		pPlayer->PushawayTouch( props[i] );

		// We can get right up next to rotating doors before they start to move, so scale back our force so we don't go flying
		if ( FClassnameIs( props[i], "func_door_rotating" ) || FClassnameIs( props[i], "prop_door_rotating" ) )
#endif
		{
			flForce *= 0.25f;
		}

		vPushAway *= flForce;

		pCmd->forwardmove += vPushAway.Dot( currentdir );
		pCmd->sidemove    += vPushAway.Dot( rightdir );
	}
}
	void CBaseGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity )
	{
		//Assume all surfaces have the same elasticity
		float flSurfaceElasticity = 1.0;

		//Don't bounce off of players with perfect elasticity
		if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
		{
			flSurfaceElasticity = 0.3;
		}

		// if its breakable glass and we kill it, don't bounce.
		// give some damage to the glass, and if it breaks, pass 
		// through it.
		bool breakthrough = false;

		if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) )
		{
			breakthrough = true;
		}

		if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) )
		{
			breakthrough = true;
		}

		if (breakthrough)
		{
			CTakeDamageInfo info( this, this, 10, DMG_CLUB );
			trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace );

			ApplyMultiDamage();

			if( trace.m_pEnt->m_iHealth <= 0 )
			{
				// slow our flight a little bit
				Vector vel = GetAbsVelocity();

				vel *= 0.4;

				SetAbsVelocity( vel );
				return;
			}
		}
		
		float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
		flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );

		// NOTE: A backoff of 2.0f is a reflection
		Vector vecAbsVelocity;
		PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
		vecAbsVelocity *= flTotalElasticity;

		// Get the total velocity (player + conveyors, etc.)
		VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity );
		float flSpeedSqr = DotProduct( vecVelocity, vecVelocity );

		// Stop if on ground.
		if ( trace.plane.normal.z > 0.7f )			// Floor
		{
			// Verify that we have an entity.
			CBaseEntity *pEntity = trace.m_pEnt;
			Assert( pEntity );

			SetAbsVelocity( vecAbsVelocity );

			if ( flSpeedSqr < ( 30 * 30 ) )
			{
				if ( pEntity->IsStandable() )
				{
					SetGroundEntity( pEntity );
				}

				// Reset velocities.
				SetAbsVelocity( vec3_origin );
				SetLocalAngularVelocity( vec3_angle );

				//align to the ground so we're not standing on end
				QAngle angle;
				VectorAngles( trace.plane.normal, angle );

				// rotate randomly in yaw
				angle[1] = random->RandomFloat( 0, 360 );

				// TODO: rotate around trace.plane.normal
				
				SetAbsAngles( angle );			
			}
			else
			{
				Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;	
				Vector vecBaseDir = GetBaseVelocity();
				VectorNormalize( vecBaseDir );
				float flScale = vecDelta.Dot( vecBaseDir );

				VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); 
				VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity );
				PhysicsPushEntity( vecVelocity, &trace );
			}
		}
		else
		{
			// If we get *too* slow, we'll stick without ever coming to rest because
			// we'll get pushed down by gravity faster than we can escape from the wall.
			if ( flSpeedSqr < ( 30 * 30 ) )
			{
				// Reset velocities.
				SetAbsVelocity( vec3_origin );
				SetLocalAngularVelocity( vec3_angle );
			}
			else
			{
				SetAbsVelocity( vecAbsVelocity );
			}
		}
		
		BounceSound();
	}
Ejemplo n.º 8
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBaseDoor::Spawn()
{
	Precache();

#ifdef HL1_DLL
	SetSolid( SOLID_BSP );
#else
	if ( GetMoveParent() && GetRootMoveParent()->GetSolid() == SOLID_BSP )
	{
		SetSolid( SOLID_BSP );
	}
	else
	{
		SetSolid( SOLID_VPHYSICS );
	}
#endif

	// Convert movedir from angles to a vector
	QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z );
	AngleVectors( angMoveDir, &m_vecMoveDir );

	SetModel( STRING( GetModelName() ) );
	m_vecPosition1	= GetLocalOrigin();

	// Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
	Vector vecOBB = CollisionProp()->OBBSize();
	vecOBB -= Vector( 2, 2, 2 );
	m_vecPosition2	= m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecOBB ) - m_flLip));

	if ( !IsRotatingDoor() )
	{
		if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) || HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
		{	// swap pos1 and pos2, put door at pos2
			UTIL_SetOrigin( this, m_vecPosition2);
			m_toggle_state = TS_AT_TOP;
		}
		else
		{
			m_toggle_state = TS_AT_BOTTOM;
		}
	}

	if (HasSpawnFlags(SF_DOOR_LOCKED))
	{
		m_bLocked = true;
	}

	SetMoveType( MOVETYPE_PUSH );
	
	if (m_flSpeed == 0)
	{
		m_flSpeed = 100;
	}
	
	SetTouch( &CBaseDoor::DoorTouch );

	if ( !FClassnameIs( this, "func_water" ) )
	{
		if ( HasSpawnFlags(SF_DOOR_PASSABLE) )
		{
			//normal door
			AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
			AddSolidFlags( FSOLID_NOT_SOLID );
		}

		if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
		{
			SetCollisionGroup( COLLISION_GROUP_PASSABLE_DOOR );
			// HACKHACK: Set this hoping that any children of the door that get blocked by the player
			// will get fixed up by vphysics
			// NOTE: We could decouple this as a separate behavior, but managing player collisions is already complex enough.
			// NOTE: This is necessary to prevent the player from blocking the wrecked train car in ep2_outland_01
			AddFlag( FL_UNBLOCKABLE_BY_PLAYER );
		}
		if ( m_bIgnoreDebris )
		{
			// both of these flags want to set the collision group and 
			// there isn't a combo group
			Assert( !HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) );
			if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
			{
				Warning("Door %s with conflicting collision settings, removing ignoredebris\n", GetDebugName() );
			}
			else
			{
				SetCollisionGroup( COLLISION_GROUP_INTERACTIVE );
			}
		}
	}

	if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) && HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
	{
		Warning("Door %s using obsolete 'Start Open' spawnflag with 'Spawn Position' set to 'Open'. Reverting to old behavior.\n", GetDebugName() );
	}

	CreateVPhysics();
}
Ejemplo n.º 9
0
bool CBaseDoor::ShouldSavePhysics()
{
	// don't save physics if you're func_water
	return !FClassnameIs( this, "func_water" );
}
Ejemplo n.º 10
0
bool CFuncMoveLinear::ShouldSavePhysics( void )
{
	// don't save physics for func_water_analog, regen
	return !FClassnameIs( this, "func_water_analog" );
		
}
Ejemplo n.º 11
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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 (FClassnameIs(pOther, "func_breakable"))
		{
			CBreakable* pOtherEntity = static_cast<CBreakable*> (pOther);
			if (pOtherEntity->GetMaterialType() == matGlass)
				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 );
				}
				if (m_pGlowTrail != NULL)
				{
					m_pGlowTrail->TurnOn();
					m_pGlowTrail->FadeAndDie(6.0f);
				}
				CBaseEntity *tmp = CreateEntityByName("item_ammo_custom");
				if (tmp)
				{
					tmp->KeyValue("origin", GetAbsOrigin());
					tmp->KeyValue("angles", vForward);
					tmp->KeyValue("model", "");
					tmp->KeyValue("ammoName", "XBowBolt");
					tmp->KeyValue("ammoCount", 1);
					tmp->SetGravity(0);
					tmp->SetMoveType(MOVETYPE_NONE);
					DispatchSpawn(tmp);
				}
			}
			
			// 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: Intercept damage and decide whether or not we want to trigger
// Input  : &info - 
//-----------------------------------------------------------------------------
int CWeaponStriderBuster::OnTakeDamage( const CTakeDamageInfo &info )
{
	// If we're attached, any damage from the player makes us trigger
	CBaseEntity *pInflictor = info.GetInflictor();
	CBaseEntity *pAttacker = info.GetAttacker();
	bool bInflictorIsPlayer = ( pInflictor != NULL && pInflictor->IsPlayer() );
	bool bAttackerIsPlayer = ( pAttacker != NULL && pAttacker->IsPlayer() );

	if ( GetParent() && GetParent()->ClassMatches( g_iszVehicle ) )
	{
		return 0;
	}

	// Only take damage from a player, for the moment
	if ( striderbuster_allow_all_damage.GetBool() || ( IsAttachedToStrider() && ( bAttackerIsPlayer || bInflictorIsPlayer ) ) )
	{
		Detonate();
		return 0;
	}

	if ( pAttacker && ( pAttacker->Classify() == CLASS_COMBINE || pAttacker->Classify() == CLASS_COMBINE_HUNTER ) )
	{
		if ( VPhysicsGetObject() && !VPhysicsGetObject()->IsMoveable() )
		{
			return 0;
		}
	}

	// Hunters are able to destroy strider busters
	if ( hunter_hate_held_striderbusters.GetBool() || hunter_hate_thrown_striderbusters.GetBool() || hunter_hate_attached_striderbusters.GetBool() )
	{
		if ( ( GetHealth() > 0 ) && ( pInflictor != NULL ) && FClassnameIs( pInflictor, "hunter_flechette" ) )
		{
			//
			// Flechette impacts don't hurt the striderbuster unless it's attached to a strider,
			// but the explosions always do. This is so that held or thrown striderbusters fly
			// awry because of the flechette, but attached striderbusters break instantly to make
			// the hunters more effective at defending the strider.
			//
			if ( IsAttachedToStrider() || !( info.GetDamageType() & DMG_NEVERGIB ) )
			{
				if( striderbuster_die_detach.GetBool() && IsAttachedToStrider() )
				{
					// Make the buster fall off and break.
					m_takedamage = DAMAGE_NO;

					CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(GetOwnerEntity());
					Assert( pStrider != NULL );
					pStrider->StriderBusterDetached( this );
					DestroyConstraint();

					// Amplify some lateral force.
					Vector vecForce = info.GetDamageForce();
					vecForce.z = 0.0f;
					VPhysicsGetObject()->ApplyForceCenter( vecForce * 5.0f );

					SetContextThink( NULL, gpGlobals->curtime, s_pBusterPingThinkContext );

					SetThink( &CWeaponStriderBuster::BusterDetachThink );
					SetNextThink( gpGlobals->curtime );
					m_iBusterFlags |= STRIDERBUSTER_FLAG_KNOCKED_OFF_STRIDER;

					return 0;
				}
				else
				{
					// Destroy the buster in place
					// Make sure they know it blew up prematurely.
					EmitSound( "Weapon_StriderBuster.Dud_Detonate" );
					DispatchParticleEffect( "striderbuster_break_flechette", GetAbsOrigin(), GetAbsAngles() );
					SetHealth( 0 );

					Shatter( info.GetAttacker() );
					return 0;
				}
			}

			if ( info.GetDamage() < 5 )
			{
				bool bFirst = ( m_CarryAngles.x == 45 && m_CarryAngles.y == 0 && m_CarryAngles.z == 0);
				float sinTime = sin( gpGlobals->curtime );
				bool bSubtractX = ( bFirst ) ? ( sinTime < 0 ) : ( m_CarryAngles.x < 45 );

				m_CarryAngles.x += ( 10.0 + 10.0 * fabsf( sinTime ) + random->RandomFloat( -2.5, 2.5 ) + random->RandomFloat( -2.5, 2.5 ) ) * ( ( bSubtractX ) ? -1.0 : 1.0 );
				m_CarryAngles.y = 15 * ( sin( gpGlobals->curtime ) + cos( gpGlobals->curtime * 0.5 ) ) * .5  + random->RandomFloat( -15, 15 );
				m_CarryAngles.z = 7.5 * ( sin( gpGlobals->curtime ) + sin( gpGlobals->curtime * 2.0 ) ) * .5 + random->RandomFloat( -7.5, 7.5 );
			}

			return 1;
		}
	}
	
	// Allow crushing damage
	if ( info.GetDamageType() & DMG_CRUSH )
		return BaseClass::OnTakeDamage( info );

	return 0;
}
Ejemplo n.º 13
0
// this function only gets called in multiplayer
void CCrossbow::FireSniperBolt()
{
	m_flNextPrimaryAttack = gpGlobals->time + 0.75;

	if (m_iClip == 0)
	{
		PlayEmptySound( );
		return;
	}

	TraceResult tr;

	m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
	m_iClip--;

	// make twang sound
	EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));

	if (m_iClip)
	{
		EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
		SendWeaponAnim( CROSSBOW_FIRE1 );
	}
	else if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0)
	{
		SendWeaponAnim( CROSSBOW_FIRE3 );
	}

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
	
	Vector anglesAim = m_pPlayer->pev->viewangles + m_pPlayer->pev->punchangle;
	UTIL_MakeVectors( anglesAim );
	Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2;
	Vector vecDir = gpGlobals->v_forward;

	UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr);

	if ( tr.pHit->v.takedamage )
	{
		switch( RANDOM_LONG(0,1) )
		{
		case 0:
			EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break;
		case 1:
			EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break;
		}

		ClearMultiDamage( );
		CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); 
		ApplyMultiDamage( pev, m_pPlayer->pev );
	}
	else
	{
		// create a bolt
		CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate();
		pBolt->pev->origin = tr.vecEndPos - vecDir * 10;
		pBolt->pev->angles = UTIL_VecToAngles( vecDir );
		pBolt->pev->solid = SOLID_NOT;
		pBolt->SetTouch( NULL );
		pBolt->SetThink( SUB_Remove );

		EMIT_SOUND( pBolt->edict(), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM );

		if (UTIL_PointContents(tr.vecEndPos) != CONTENTS_WATER)
		{
			UTIL_Sparks( tr.vecEndPos );
		}

		if ( FClassnameIs( tr.pHit, "worldspawn" ) )
		{
			// let the bolt sit around for a while if it hit static architecture
			pBolt->pev->nextthink = gpGlobals->time + 5.0;
		}
		else
		{
			pBolt->pev->nextthink = gpGlobals->time;
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
void CNPC_CombineAce::Event_Killed( const CTakeDamageInfo &info )
{
	if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && info.GetDamageType() & (DMG_BLAST | DMG_CRUSH) && !(info.GetDamageType() & (DMG_DISSOLVE)) && !PlayerHasMegaPhysCannon())
	{
		Vector vecDamageDir = info.GetDamageForce();
		SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage());
		DispatchParticleEffect("headshotspray", GetAbsOrigin(), GetAbsAngles(), this);
		EmitSound("Gore.Headshot");
		float flFadeTime = 25.0;

		CGib::SpawnSpecificGibs(this, 1, 750, 1500, "models/gibs/soldier_ace_head.mdl", flFadeTime);

		Vector vecRagForce;
		vecRagForce.x = random->RandomFloat(-400, 400);
		vecRagForce.y = random->RandomFloat(-400, 400);
		vecRagForce.z = random->RandomFloat(0, 250);

		Vector vecRagDmgForce = (vecRagForce + vecDamageDir);

		CBaseEntity *pLeftArmGib = CreateRagGib("models/gibs/soldier_ace_left_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pLeftArmGib)
		{
			color32 color = pLeftArmGib->GetRenderColor();
			pLeftArmGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pRightArmGib = CreateRagGib("models/gibs/soldier_ace_right_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pRightArmGib)
		{
			color32 color = pRightArmGib->GetRenderColor();
			pRightArmGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pTorsoGib = CreateRagGib("models/gibs/soldier_ace_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pTorsoGib)
		{
			color32 color = pTorsoGib->GetRenderColor();
			pTorsoGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pPelvisGib = CreateRagGib("models/gibs/soldier_ace_pelvis.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pPelvisGib)
		{
			color32 color = pPelvisGib->GetRenderColor();
			pPelvisGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pLeftLegGib = CreateRagGib("models/gibs/soldier_ace_left_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pLeftLegGib)
		{
			color32 color = pLeftLegGib->GetRenderColor();
			pLeftLegGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pRightLegGib = CreateRagGib("models/gibs/soldier_ace_right_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pRightLegGib)
		{
			color32 color = pRightLegGib->GetRenderColor();
			pRightLegGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		//now add smaller gibs.
		CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p3.mdl", flFadeTime);
		CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p4.mdl", flFadeTime);

		if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
		{
			pArmor->Remove();
			DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));
		}

		Vector forceVector = CalcDamageForceVector(info);

		// Drop any weapon that I own
		if (VPhysicsGetObject())
		{
			Vector weaponForce = forceVector * VPhysicsGetObject()->GetInvMass();
			Weapon_Drop(m_hActiveWeapon, NULL, &weaponForce);
		}
		else
		{
			Weapon_Drop(m_hActiveWeapon);
		}

		if (info.GetAttacker()->IsPlayer())
		{
			((CSingleplayRules*)GameRules())->NPCKilled(this, info);
		}

		UTIL_Remove(this);
		SetThink(NULL);
		return;
	}

	// Don't bother if we've been told not to, or the player has a megaphyscannon
	if ( combine_ace_spawn_health.GetBool() == false || PlayerHasMegaPhysCannon() )
	{
		BaseClass::Event_Killed( info );
		return;
	}

	SetEyeState(ACE_EYE_DEAD);

	if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
	{
		pArmor->Remove();
	}

	CBasePlayer *pPlayer = ToBasePlayer( info.GetAttacker() );

	if ( !pPlayer )
	{
		CPropVehicleDriveable *pVehicle = dynamic_cast<CPropVehicleDriveable *>( info.GetAttacker() ) ;
		if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() )
		{
			pPlayer = assert_cast<CBasePlayer *>( pVehicle->GetDriver() );
		}
	}

	if ( pPlayer != NULL )
	{
		// Elites drop alt-fire ammo, so long as they weren't killed by dissolving.
#ifdef HL2_EPISODIC
		if (HasSpawnFlags(SF_COMBINE_NO_AR2DROP) == false)
#endif
		{
			if (FClassnameIs(GetActiveWeapon(), "weapon_ar2"))
			{
				CBaseEntity *pItem = DropItem("item_ammo_ar2_altfire", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));

				if (pItem)
				{
					IPhysicsObject *pObj = pItem->VPhysicsGetObject();

					if (pObj)
					{
						Vector			vel = RandomVector(-64.0f, 64.0f);
						AngularImpulse	angImp = RandomAngularImpulse(-300.0f, 300.0f);

						vel[2] = 0.0f;
						pObj->AddVelocity(&vel, &angImp);
					}

					if (info.GetDamageType() & DMG_DISSOLVE)
					{
						CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem);

						if (pAnimating)
						{
							pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL);
						}
					}
					else
					{
						WeaponManager_AddManaged(pItem);
					}
				}
			}
			else if (FClassnameIs(GetActiveWeapon(), "weapon_smg1"))
			{
				CBaseEntity *pItem = DropItem("item_ammo_smg1_grenade", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));

				if (pItem)
				{
					IPhysicsObject *pObj = pItem->VPhysicsGetObject();

					if (pObj)
					{
						Vector			vel = RandomVector(-64.0f, 64.0f);
						AngularImpulse	angImp = RandomAngularImpulse(-300.0f, 300.0f);

						vel[2] = 0.0f;
						pObj->AddVelocity(&vel, &angImp);
					}

					if (info.GetDamageType() & DMG_DISSOLVE)
					{
						CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem);

						if (pAnimating)
						{
							pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL);
						}
					}
					else
					{
						WeaponManager_AddManaged(pItem);
					}
				}
			}
		}

		CHalfLife2 *pHL2GameRules = static_cast<CHalfLife2 *>(g_pGameRules);

		// Attempt to drop health
		if ( pHL2GameRules->NPC_ShouldDropHealth( pPlayer ) )
		{
			DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) );
			pHL2GameRules->NPC_DroppedHealth();
		}

		if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
		{
			DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));
		}
	}

	BaseClass::Event_Killed( info );
}
Ejemplo n.º 15
0
/* <485ecf> ../cstrike/dlls/hostage/hostage_localnav.cpp:472 */
int CLocalNav::PathTraversable(Vector &vecSource, Vector &vecDest, int fNoMonsters)
{
	TraceResult tr;
	Vector vecSrcTmp;
	Vector vecDestTmp;
	Vector vecDir;
	float_precision flTotal;
	int retval = PATH_TRAVERSABLE_EMPTY;

	vecSrcTmp = vecSource;
	vecDestTmp = vecDest - vecSource;

	vecDir = vecDestTmp.NormalizePrecision();
	vecDir.z = 0;

	flTotal = vecDestTmp.Length2D();

	while (flTotal > 1.0)
	{
		if (flTotal >= s_flStepSize)
		{
#ifndef PLAY_GAMEDLL
			vecDestTmp = vecSrcTmp + (vecDir * s_flStepSize);
#else
			// TODO: fix test demo
			vecDestTmp[0] = vecSrcTmp[0] + (vecDir[0] * s_flStepSize);
			vecDestTmp[1] = vecSrcTmp[1] + (float)(vecDir[1] * s_flStepSize);
			vecDestTmp[2] = vecSrcTmp[2] + (vecDir[2] * s_flStepSize);
#endif // PLAY_GAMEDLL

		}
		else
			vecDestTmp = vecDest;

		m_fTargetEntHit = FALSE;

		if (PathClear(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
		{
			vecDestTmp = tr.vecEndPos;

			if (retval == PATH_TRAVERSABLE_EMPTY)
			{
				retval = PATH_TRAVERSABLE_SLOPE;
			}
		}
		else
		{
			if (tr.fStartSolid)
			{
				return PATH_TRAVERSABLE_EMPTY;
			}

			if (tr.pHit && !fNoMonsters && tr.pHit->v.classname)
			{
				if (FClassnameIs(tr.pHit, "hostage_entity"))
				{
					return PATH_TRAVERSABLE_EMPTY;
				}
			}

			vecSrcTmp = tr.vecEndPos;

			if (tr.vecPlaneNormal.z <= 0.7)
			{
				if (StepTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					if (retval == PATH_TRAVERSABLE_EMPTY)
					{
						retval = PATH_TRAVERSABLE_STEP;
					}
				}
				else
				{
					if (!StepJumpable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
					{
						return PATH_TRAVERSABLE_EMPTY;
					}

					if (retval == PATH_TRAVERSABLE_EMPTY)
					{
						retval = PATH_TRAVERSABLE_STEPJUMPABLE;
					}
				}
			}
			else
			{
				if (!SlopeTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					return PATH_TRAVERSABLE_EMPTY;
				}

				if (retval == PATH_TRAVERSABLE_EMPTY)
				{
					retval = PATH_TRAVERSABLE_SLOPE;
				}
			}
		}

		Vector vecDropDest = vecDestTmp - Vector(0, 0, 300);

		if (PathClear(vecDestTmp, vecDropDest, fNoMonsters, tr))
		{
			return PATH_TRAVERSABLE_EMPTY;
		}

		if (!tr.fStartSolid)
			vecDestTmp = tr.vecEndPos;

		vecSrcTmp = vecDestTmp;

		BOOL fProgressThisTime = m_fTargetEntHit;
		Vector vecSrcThisTime = vecDest - vecDestTmp;

		if (fProgressThisTime)
			break;

		flTotal = vecSrcThisTime.Length2D();
	}

	vecDest = vecDestTmp;

	return retval;
}
Ejemplo n.º 16
0
void CScientist :: StartTask( Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_SAY_HEAL:
//		if ( FOkToSpeak() )
		Talk( 2 );
		m_hTalkTarget = m_hTargetEnt;
		if ( FClassnameIs(pev, "monster_rosenberg"))
			PlaySentence( "RO_HEAL", 2, VOL_NORM, ATTN_IDLE );
                    else	PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE );
		TaskComplete();
		break;

	case TASK_SCREAM:
		Scream();
		TaskComplete();
		break;

	case TASK_RANDOM_SCREAM:
		if ( RANDOM_FLOAT( 0, 1 ) < pTask->flData )
			Scream();
		TaskComplete();
		break;

	case TASK_SAY_FEAR:
		if ( FOkToSpeak() )
		{
			Talk( 2 );
			m_hTalkTarget = m_hEnemy;
			if ( FClassnameIs(pev, "monster_rosenberg"))
			{
				PlaySentence( "RO_FEAR", 5, VOL_NORM, ATTN_NORM );
			}			
			else
			{
				if ( m_hEnemy->IsPlayer() )
					PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM );
				else	PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM );
			}
		}
		TaskComplete();
		break;

	case TASK_HEAL:
		m_IdealActivity = ACT_MELEE_ATTACK1;
		break;

	case TASK_RUN_PATH_SCARED:
		m_movementActivity = ACT_RUN_SCARED;
		break;

	case TASK_MOVE_TO_TARGET_RANGE_SCARED:
		{
			if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 )
				TaskComplete();
			else
			{
				m_vecMoveGoal = m_hTargetEnt->pev->origin;
				if ( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) )
					TaskFail();
			}
		}
		break;

	default:
		CTalkMonster::StartTask( pTask );
		break;
	}
}
Ejemplo n.º 17
0
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore )
{
	const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX);
	CBaseEntity *pEntity = NULL;
	trace_t		tr;
	float		flAdjustedDamage, falloff;
	Vector		vecSpot;

	Vector vecSrc = vecSrcIn;

	if ( flRadius )
		falloff = info.GetDamage() / flRadius;
	else
		falloff = 1.0;

	int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false;

#ifdef HL2_DLL
	if( bInWater )
	{
		// Only muffle the explosion if deeper than 2 feet in water.
		if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) )
		{
			bInWater = false;
		}
	}
#endif // HL2_DLL
	
	vecSrc.z += 1;// in case grenade is lying on the ground

	float flHalfRadiusSqr = Square( flRadius / 2.0f );

	// iterate on all entities in the vicinity.
	for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() )
	{
		// This value is used to scale damage when the explosion is blocked by some other object.
		float flBlockedDamagePercent = 0.0f;

		if ( pEntity == pEntityIgnore )
			continue;

		if ( pEntity->m_takedamage == DAMAGE_NO )
			continue;

		// UNDONE: this should check a damage mask, not an ignore
		if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore )
		{// houndeyes don't hurt other houndeyes with their attack
			continue;
		}

		// blast's don't tavel into or out of water
		if (bInWater && pEntity->GetWaterLevel() == 0)
			continue;

		if (!bInWater && pEntity->GetWaterLevel() == 3)
			continue;

		// Check that the explosion can 'see' this entity.
		vecSpot = pEntity->BodyTarget( vecSrc, false );
		UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr );

		if( old_radius_damage.GetBool() )
		{
			if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity )
			continue;
		}
		else
		{
			if ( tr.fraction != 1.0 )
			{
				if ( IsExplosionTraceBlocked(&tr) )
				{
					if( ShouldUseRobustRadiusDamage( pEntity ) )
					{
						if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr )
						{
							// Only use robust model on a target within one-half of the explosion's radius.
							continue;
						}

						Vector vecToTarget = vecSpot - tr.endpos;
						VectorNormalize( vecToTarget );

						// We're going to deflect the blast along the surface that 
						// interrupted a trace from explosion to this target.
						Vector vecUp, vecDeflect;
						CrossProduct( vecToTarget, tr.plane.normal, vecUp );
						CrossProduct( tr.plane.normal, vecUp, vecDeflect );
						VectorNormalize( vecDeflect );

						// Trace along the surface that intercepted the blast...
						UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr );
						//NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 );

						// ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated.
						UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr );
						//NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 );

						if( tr.fraction != 1.0 && tr.DidHitWorld() )
						{
							// Still can't reach the target.
							continue;
						}
						// else fall through
					}
					else
					{
						continue;
					}
				}

				// UNDONE: Probably shouldn't let children block parents either?  Or maybe those guys should set their owner if they want this behavior?
				// HL2 - Dissolve damage is not reduced by interposing non-world objects
				if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity )
				{
					// Some entity was hit by the trace, meaning the explosion does not have clear
					// line of sight to the entity that it's trying to hurt. If the world is also
					// blocking, we do no damage.
					CBaseEntity *pBlockingEntity = tr.m_pEnt;
					//Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() );

					UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr );

					if( tr.fraction != 1.0 )
					{
						continue;
					}
					
					// Now, if the interposing object is physics, block some explosion force based on its mass.
					if( pBlockingEntity->VPhysicsGetObject() )
					{
						const float MASS_ABSORB_ALL_DAMAGE = 350.0f;
						float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass();
						float scale = flMass / MASS_ABSORB_ALL_DAMAGE;

						// Absorbed all the damage.
						if( scale >= 1.0f )
						{
							continue;
						}

						ASSERT( scale > 0.0f );
						flBlockedDamagePercent = scale;
						//Msg("  Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f);
					}
					else
					{
						// Some object that's not the world and not physics. Generically block 25% damage
						flBlockedDamagePercent = 0.25f;
					}
				}
			}
		}
		// decrease damage for an ent that's farther from the bomb.
		flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff;
		flAdjustedDamage = info.GetDamage() - flAdjustedDamage;

		if ( flAdjustedDamage <= 0 )
		{
			continue;
		}

		// the explosion can 'see' this entity, so hurt them!
		if (tr.startsolid)
		{
			// if we're stuck inside them, fixup the position and distance
			tr.endpos = vecSrc;
			tr.fraction = 0.0;
		}
		
		CTakeDamageInfo adjustedInfo = info;
		//Msg("%s: Blocked damage: %f percent (in:%f  out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) );
		adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) );

		// Now make a consideration for skill level!
		if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() )
		{
			// An explosion set off by the player is harming an NPC. Adjust damage accordingly.
			adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel();
		}

		Vector dir = vecSpot - vecSrc;
		VectorNormalize( dir );

		// If we don't have a damage force, manufacture one
		if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin )
		{
			if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) )
			{
				CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc );
			}
		}
		else
		{
			// Assume the force passed in is the maximum force. Decay it based on falloff.
			float flForce = adjustedInfo.GetDamageForce().Length() * falloff;
			adjustedInfo.SetDamageForce( dir * flForce );
			adjustedInfo.SetDamagePosition( vecSrc );
		}

		if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt )
		{
			ClearMultiDamage( );
			pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr );
			ApplyMultiDamage();
		}
		else
		{
			pEntity->TakeDamage( adjustedInfo );
		}

		// Now hit all triggers along the way that respond to damage... 
		pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir );

#if defined( GAME_DLL )
		if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) )
		{

			// This is a total hack!!!
			bool bIsPrimary = true;
			CBasePlayer *player = ToBasePlayer( info.GetAttacker() );
			CBaseCombatWeapon *pWeapon = player->GetActiveWeapon();
			if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) )
			{
				bIsPrimary = false;
			}

			gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info );
		}
#endif
	}
}
Ejemplo n.º 18
0
// Init talk data
void CScientist :: TalkInit()
{
	
	CTalkMonster::TalkInit();

	// scientist will try to talk to friends in this order:

	m_szFriends[0] = "monster_scientist";
	m_szFriends[1] = "monster_sitting_scientist";
	m_szFriends[2] = "monster_barney";

	// scientists speach group names (group names are in sentences.txt)
	if ( FClassnameIs(pev, "monster_rosenberg"))
	{
          	m_szGrp[TLK_ANSWER]  =	"RO_ANSWER";
		m_szGrp[TLK_QUESTION] =	"RO_QUESTION";
		m_szGrp[TLK_IDLE] =		"RO_IDLE";
		m_szGrp[TLK_STARE] =	"RO_STARE";
		m_szGrp[TLK_USE] =		"RO_OK";
		m_szGrp[TLK_UNUSE] =	"RO_WAIT";
		m_szGrp[TLK_STOP] =		"RO_STOP";
		m_szGrp[TLK_NOSHOOT] =	"RO_SCARED";
		m_szGrp[TLK_HELLO] =	"RO_HELLO";

		m_szGrp[TLK_PLHURT1] =	"!RO_CUREA";
		m_szGrp[TLK_PLHURT2] =	"!RO_CUREB"; 
		m_szGrp[TLK_PLHURT3] =	"!RO_CUREC";

		m_szGrp[TLK_PHELLO] =	"RO_PHELLO";
		m_szGrp[TLK_PIDLE] =	"RO_PIDLE";
		m_szGrp[TLK_PQUESTION] = 	"RO_PQUEST";
		m_szGrp[TLK_SMELL] =	"RO_SMELL";
	
		m_szGrp[TLK_WOUND] =	"RO_WOUND";
		m_szGrp[TLK_MORTAL] =	"RO_MORTAL";
	}
	else
	{
		m_szGrp[TLK_ANSWER]  =	"SC_ANSWER";
		m_szGrp[TLK_QUESTION] =	"SC_QUESTION";
		m_szGrp[TLK_IDLE] =		"SC_IDLE";
		m_szGrp[TLK_STARE] =	"SC_STARE";
		m_szGrp[TLK_USE] =		"SC_OK";
		m_szGrp[TLK_UNUSE] =	"SC_WAIT";
		m_szGrp[TLK_STOP] =		"SC_STOP";
		m_szGrp[TLK_NOSHOOT] =	"SC_SCARED";
		m_szGrp[TLK_HELLO] =	"SC_HELLO";

		m_szGrp[TLK_PLHURT1] =	"!SC_CUREA";
		m_szGrp[TLK_PLHURT2] =	"!SC_CUREB"; 
		m_szGrp[TLK_PLHURT3] =	"!SC_CUREC";

		m_szGrp[TLK_PHELLO] =	"SC_PHELLO";
		m_szGrp[TLK_PIDLE] =	"SC_PIDLE";
		m_szGrp[TLK_PQUESTION] = 	"SC_PQUEST";
		m_szGrp[TLK_SMELL] =	"SC_SMELL";
	
		m_szGrp[TLK_WOUND] =	"SC_WOUND";
		m_szGrp[TLK_MORTAL] =	"SC_MORTAL";
          }
          
	// get voice for head
	switch (pev->body % 3)
	{
	default:
	case HEAD_GLASSES:	m_voicePitch = 105; break;	//glasses
	case HEAD_EINSTEIN: m_voicePitch = 100; break;	//einstein
	case HEAD_LUTHER:	m_voicePitch = 95;  break;	//luther
	case HEAD_SLICK:	m_voicePitch = 85;  break;	//slick
	}
}
Ejemplo n.º 19
0
bool IsBreakableEntity( CBaseEntity *pEnt )
{
	if ( pEnt == NULL )
		return false;

	// If we won't be able to break it, don't try
	if ( pEnt->m_takedamage != DAMAGE_YES )
		return false;

	if ( pEnt->GetCollisionGroup() != COLLISION_GROUP_PUSHAWAY && pEnt->GetCollisionGroup() != COLLISION_GROUP_BREAKABLE_GLASS && pEnt->GetCollisionGroup() != COLLISION_GROUP_NONE )
		return false;

	if ( pEnt->m_iHealth > 200 )
		return false;

	IMultiplayerPhysics *pPhysicsInterface = dynamic_cast< IMultiplayerPhysics * >( pEnt );
	if ( pPhysicsInterface )
	{
		if ( pPhysicsInterface->GetMultiplayerPhysicsMode() != PHYSICS_MULTIPLAYER_SOLID )
			return false;
	}
	else
	{
		if ((FClassnameIs( pEnt, "func_breakable" ) || FClassnameIs( pEnt, "func_breakable_surf" )))
		{
			if (FClassnameIs( pEnt, "func_breakable_surf" ))
			{
				// don't try to break it if it has already been broken
				CBreakableSurface *surf = static_cast< CBreakableSurface * >( pEnt );

				if ( surf->m_bIsBroken )
					return false;
			}
		}
		else if ( pEnt->PhysicsSolidMaskForEntity() & CONTENTS_PLAYERCLIP )
		{
			// hostages and players use CONTENTS_PLAYERCLIP, so we can use it to ignore them
			return false;
		}
	}

	IBreakableWithPropData *pBreakableInterface = dynamic_cast< IBreakableWithPropData * >( pEnt );
	if ( pBreakableInterface )
	{
		// Bullets don't damage it - ignore
		if ( pBreakableInterface->GetDmgModBullet() <= 0.0f )
		{
			return false;
		}
	}

	CBreakableProp *pProp = dynamic_cast< CBreakableProp * >( pEnt );
	if ( pProp )
	{
		// It takes a large amount of damage to even scratch it - ignore
		if ( pProp->m_iMinHealthDmg >= 50 )
		{
			return false;
		}
	}

	return true;
}
Ejemplo n.º 20
0
Schedule_t *CScientist :: GetSchedule ( void )
{
	// so we don't keep calling through the EHANDLE stuff
	CBaseEntity *pEnemy = m_hEnemy;

	if ( HasConditions( bits_COND_HEAR_SOUND ) )
	{
		CSound *pSound;
		pSound = PBestSound();

		ASSERT( pSound != NULL );
		if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
			return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
	}

	switch( m_MonsterState )
	{
	case MONSTERSTATE_ALERT:	
	case MONSTERSTATE_IDLE:
		if ( pEnemy )
		{
			if ( HasConditions( bits_COND_SEE_ENEMY ) )
				m_fearTime = gpGlobals->time;
			else if ( DisregardEnemy( pEnemy ) )		// After 15 seconds of being hidden, return to alert
			{
				m_hEnemy = NULL;
				pEnemy = NULL;
			}
		}

		if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
		{
			// flinch if hurt
			return GetScheduleOfType( SCHED_SMALL_FLINCH );
		}

		// Cower when you hear something scary
		if ( HasConditions( bits_COND_HEAR_SOUND ) )
		{
			CSound *pSound;
			pSound = PBestSound();

			ASSERT( pSound != NULL );
			if ( pSound )
			{
				if ( pSound->m_iType & (bits_SOUND_DANGER | bits_SOUND_COMBAT) )
				{
					if ( gpGlobals->time - m_fearTime > 3 )	// Only cower every 3 seconds or so
					{
						m_fearTime = gpGlobals->time;		// Update last fear
						return GetScheduleOfType( SCHED_STARTLE );	// This will just duck for a second
					}
				}
			}
		}

		// Behavior for following the player
		if ( IsFollowing() )
		{
			if ( !m_hTargetEnt->IsAlive() )
			{
				// UNDONE: Comment about the recently dead player here?
				StopFollowing( FALSE );
				break;
			}

			int relationship = R_NO;

			// Nothing scary, just me and the player
			if ( pEnemy != NULL )
				relationship = IRelationship( pEnemy );

			// UNDONE: Model fear properly, fix R_FR and add multiple levels of fear
			if ( relationship != R_DL && relationship != R_HT )
			{
				// If I'm already close enough to my target
				if ( TargetDistance() <= 128 )
				{
					if ( CanHeal() )	// Heal opportunistically
						return slHeal;
					if ( HasConditions( bits_COND_CLIENT_PUSH ) )	// Player wants me to move
						return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
				}
				return GetScheduleOfType( SCHED_TARGET_FACE );	// Just face and follow.
			}
			else if ( !FClassnameIs(pev, "monster_rosenberg")) // UNDONE: When afraid, scientist won't move out of your way.  Keep This?  If not, write move away scared
			{
				if ( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react
					return GetScheduleOfType( SCHED_FEAR );					// React to something scary
				return GetScheduleOfType( SCHED_TARGET_FACE_SCARED );	// face and follow, but I'm scared!
			}
		}

		if ( HasConditions( bits_COND_CLIENT_PUSH ) )	// Player wants me to move
			return GetScheduleOfType( SCHED_MOVE_AWAY );

		// try to say something about smells
		TrySmellTalk();
		break;
	case MONSTERSTATE_COMBAT:
		if ( HasConditions( bits_COND_NEW_ENEMY ) )
			return slFear;					// Point and scream!
		if ( HasConditions( bits_COND_SEE_ENEMY ) )
			return slScientistCover;		// Take Cover
		
		if ( HasConditions( bits_COND_HEAR_SOUND ) )
			return slTakeCoverFromBestSound;	// Cower and panic from the scary sound!

		return slScientistCover;			// Run & Cower
		break;
	}
	
	return CTalkMonster::GetSchedule();
}
//=========================================================
// 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);
								}
							}
						}
					}
				}
			}
		}
	}
}
Ejemplo n.º 22
0
void CTank :: Fire ( int canon )
{
	Vector vecGun;
	GetAttachment( canon, vecGun, Vector(0,0,0) );

	if ( !FStrEq(STRING(gpGlobals->mapname), "l3m10") && !FStrEq(STRING(gpGlobals->mapname), "l3m12")  && !FStrEq(STRING(gpGlobals->mapname), "l3m14")  )
	{			
		CSprite *pSprite = CSprite::SpriteCreate( SPRITE_SMOKE, vecGun, TRUE );
		pSprite->AnimateAndDie( 15 );
		pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation );
		pSprite->SetAttachment( edict(), canon+1 );
		pSprite->SetScale( SPRITE_SMOKE_SCALE );
	}


	TraceResult tr;

	UTIL_MakeVectors ( TourelleAngle() );
	UTIL_TraceLine( vecGun, vecGun + gpGlobals->v_forward * 8192, dont_ignore_monsters, edict(), &tr );

	// pas de dommages - la fonction standart donne un rayon 2.5 fois les dommages
	// 250 * 2.5 = 625	- bcp trop grand

	ExplosionCreate( tr.vecEndPos, pev->angles, NULL/*edict()*/, 250, FALSE );

	// on applique nous-même les dommages - rayon : 250
	::RadiusDamage( tr.vecEndPos, pev, pev, 300, 300, CLASS_NONE, DMG_BLAST );
	
	//effet de fumée
	EnvSmokeCreate( tr.vecEndPos, 4, 10, 2, NULL );

/*	// sprites de feu

	for ( int i=0; i<4; i++ )
	{
		for ( int j=0; j<3; j++ )
		{
			CSprite *pSpr = CSprite::SpriteCreate ( SPRITE_FEU, tr.vecEndPos + Vector(0,0,50), TRUE );
			pSpr->SetTransparency ( kRenderTransAdd, 255, 255, 255, 180, kRenderFxNone );

			pSpr->pev->scale		= (float)((float)SPRITE_FEU_SCALE*2*(1/(i+1)));
			pSpr->pev->framerate	= RANDOM_FLOAT(18,24);
			pSpr->pev->velocity		= Vector ( RANDOM_FLOAT(-50,50)*(3-i)/3,RANDOM_FLOAT(-50,50)*(3-i)/3, 50*(i));
			pSpr->pev->spawnflags  |= SF_SPRITE_ONCE;
			pSpr->TurnOn();
		}
	}
*/
/*	for ( i=0; i<1; i++ )
	{
		CSprite *pSpr = CSprite::SpriteCreate ( SPRITE_SMOKEBALL, Vector(pev->origin.x,pev->origin.y,pev->origin.z + 100), TRUE );
		pSpr->SetScale ( SPRITE_SMOKEBALL_SCALE );
		pSpr->AnimateAndDie ( RANDOM_FLOAT(3,4) );
		pSpr->SetTransparency ( kRenderTransAlpha, 255, 255, 255, 200, kRenderFxNone );
		pSpr->pev->velocity = Vector ( RANDOM_FLOAT(-50,50),RANDOM_FLOAT(-50,50),RANDOM_FLOAT(130,150) );
	}
*/
	//breakable spéciaux

	if ( FClassnameIs (tr.pHit, "func_breakable") && VARS(tr.pHit)->spawnflags & SF_BREAK_TANKTOUCH )
	{
		CBreakable *pBreak = (CBreakable*) CBaseEntity::Instance(tr.pHit);

		if ( pBreak->CheckTankPrev() )
		{
			pBreak->pev->health = 0;
			pBreak->Killed( pev, GIB_NORMAL );
			pBreak->Die();
		}
	}
}
Ejemplo n.º 23
0
void CRecharge::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
	// if it's not a player, ignore
	if (!FClassnameIs(pActivator->pev, "player"))
		return;

	// if there is no juice left, turn it off
	if (m_iJuice <= 0)
	{
		pev->frame = 1.0f;
		Off();
	}

	// if the player doesn't have the suit, or there is no juice left, make the deny noise
	if (m_iJuice <= 0 || !(pActivator->pev->weapons & (1 << WEAPON_SUIT)))
	{
		if (m_flSoundTime <= gpGlobals->time)
		{
			m_flSoundTime = gpGlobals->time + 0.62f;
			EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM);
		}

		return;
	}

	pev->nextthink = pev->ltime + 0.25f;
	SetThink(&CRecharge::Off);

	// Time to recharge yet?
	if (m_flNextCharge >= gpGlobals->time)
		return;

	// Make sure that we have a caller
	if (!pActivator)
		return;

	m_hActivator = pActivator;//EHANDLE::CBaseEntity *operator=

	//only recharge the player
	if (!m_hActivator->IsPlayer())
		return;

	// Play the on sound or the looping charging sound
	if (!m_iOn)
	{
		m_iOn++;
		EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM);
		m_flSoundTime = gpGlobals->time + 0.56f;
	}

	if (m_iOn == 1 && m_flSoundTime <= gpGlobals->time)
	{
		m_iOn++;
		EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM);
	}

	// charge the player
	if (m_hActivator->pev->armorvalue < 100)
	{
		m_iJuice--;
		m_hActivator->pev->armorvalue += 1.0f;

		if (m_hActivator->pev->armorvalue > 100)
			m_hActivator->pev->armorvalue = 100;
	}

	// govern the rate of charge
	m_flNextCharge = gpGlobals->time + 0.1f;
}
Ejemplo n.º 24
0
void CTank :: DriveThink ( void )
{
	pev->nextthink = gpGlobals->time + NEXTTHINK_TIME;
	StudioFrameAdvance ( );

	if ( pev->sequence == 1 )
		pev->sequence = 0;

//	ALERT ( at_console, "playerdrivetank : %s\n", m_pPlayer->m_iDrivingTank == TRUE ? "TRUE" : "FALSE" ); 

	// apres le changement de niveau, reinitialisation de la vue

	if ( bSetView == 1 )
	{
		// actualisation de la vie du bsp

		m_pTankBSP->pev->health = m_flTempHealth;

		// réglages camera & hud

		m_pCam->SetPlayerTankView ( TRUE );
		bSetView = 0;
	}

	//quitte le tank

	if (m_pPlayer->pev->button & IN_USE)
	{
		pev->velocity = pev->avelocity = m_pTankBSP->pev->velocity = m_pTankBSP->pev->avelocity =Vector (0,0,0);
		m_pTankBSP->pev->origin = pev->origin;
		m_pTankBSP->pev->angles = pev->angles;

		m_pCam->pev->velocity = ( vecCamOrigin() - m_pCam->pev->origin ) /2;
		UpdateCamAngle ( m_pCam->pev->origin, 2 );

		UpdateSound ();

		SetThink( StopThink );
		pev->nextthink = gpGlobals->time + 2;
		return;
	}


	float flNextVAngleY = pev->v_angle.y;
	float flNextVAngleX = pev->v_angle.x;
	float flNewAVelocity;
	Vector vecNewVelocity;

	//---------------------------------------------_-_-_ _  _
	//modifications de la direction de la tourelle
			
	if ( bTankOn == 0 )
	{
		bTankOn = 1;
		m_PlayerAngles.x = m_pPlayer->pev->angles.x ;
		m_PlayerAngles.y = m_pPlayer->pev->angles.y ;
	}

	if ( m_pPlayer->pev->angles.y != m_PlayerAngles.y )
	{
		int iSens;
		int iDist = ModifAngles ( m_pPlayer->pev->angles.y ) - ModifAngles ( m_PlayerAngles.y );

		if ( fabs(iDist) > 180 )
		{
			if ( iDist > 0 )
				iDist = iDist - 360;
			else
				iDist = iDist + 360;
		}

		iSens = iDist == fabs(iDist) ? 1 : -1 ;
		iDist = fabs(iDist);


		if ( iDist < TANK_TOURELLE_ROT_SPEED )
			flNextVAngleY += iDist * iSens;

		else
			flNextVAngleY += TANK_TOURELLE_ROT_SPEED * iSens;

		if ( flNextVAngleY > TOURELLE_MAX_ROT_Y )
			flNextVAngleY = TOURELLE_MAX_ROT_Y;

		if ( flNextVAngleY < -TOURELLE_MAX_ROT_Y )
			flNextVAngleY = -TOURELLE_MAX_ROT_Y;

	}

	if ( m_pPlayer->pev->angles.x != m_PlayerAngles.x )
	{
		int iSens;
		int iDist = ModifAngles ( m_pPlayer->pev->angles.x ) - ModifAngles ( m_PlayerAngles.x );

		if ( fabs(iDist) > 180 )
		{
			if ( iDist > 0 )
				iDist = iDist - 360;
			else
				iDist = iDist + 360;
		}

		iSens = iDist == fabs(iDist) ? 1 : -1 ;
		iDist = fabs(iDist);

		if ( iDist < TANK_TOURELLE_ROT_SPEED )
			flNextVAngleX += iDist * iSens;

		else
			flNextVAngleX += TANK_TOURELLE_ROT_SPEED * iSens;

		if ( flNextVAngleX > TOURELLE_MAX_ROT_X )
			flNextVAngleX = TOURELLE_MAX_ROT_X;

		if ( flNextVAngleX < TOURELLE_MAX_ROT_X2 )
			flNextVAngleX = TOURELLE_MAX_ROT_X2;

	}

	m_PlayerAngles.y = m_pPlayer->pev->angles.y;
	m_PlayerAngles.x = m_pPlayer->pev->angles.x;


	//---------------------------------
	// sons d'acceleration du tank

	float flSpeed = pev->velocity.Length();

	if ( m_flNextSound < gpGlobals->time)
	{
		if  ( (m_pPlayer->pev->button & IN_FORWARD) && ((flSpeed==0) || (m_iTankmove & MOVE_BACKWARD)) )
		{
			EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, ACCELERE_SOUND1, 1 , ATTN_NONE, 0, 100 );
			m_flNextSound = gpGlobals->time + 2.5;
		}
		else if  ( (m_pPlayer->pev->button & IN_BACK) && (m_iTankmove & MOVE_FORWARD) )
		{
			EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, DECCELERE_SOUND, 1 , ATTN_NONE, 0, 100 );
			m_flNextSound = gpGlobals->time + 2.5;
		}
		else if  ( (m_pPlayer->pev->button & IN_FORWARD) && (m_iTankmove & MOVE_FORWARD) && !(m_iTankmove & PUSH_FORWARD))
		{
			if ( RANDOM_LONG ( 0,1 ) )
				EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, ACCELERE_SOUND2, 1 , ATTN_NONE, 0, 100 );
			else
				EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, ACCELERE_SOUND3, 1 , ATTN_NONE, 0, 100 );
			m_flNextSound = gpGlobals->time + 2.5;
		}
	}


	//-------------------------------
	//modification de la vitesse du tank


	UTIL_MakeVectors( pev->angles );

	int iSens = UTIL_AngleDiff( UTIL_VecToAngles ( pev->velocity ).y,  UTIL_VecToAngles	( gpGlobals->v_forward ).y );

	if ( flSpeed == 0 )
		iSens = 0;
	else if ( iSens < -45 || iSens > 45 )
		iSens = -1;
	else 
		iSens = 1;

	if ( m_pPlayer->pev->button & IN_FORWARD)
	{
		m_iTankmove |= PUSH_FORWARD;
		m_iTankmove &= ~PUSH_BACKWARD;		

		if ( iSens == -1 )
		{
			if ( flSpeed > TANK_DECCELERATION * 2 )
				vecNewVelocity = gpGlobals->v_forward * - ( flSpeed - TANK_DECCELERATION );
			else
				vecNewVelocity = Vector ( 0,0,0 );
		}

		else if ( flSpeed < 250 )
			vecNewVelocity = gpGlobals->v_forward * ( flSpeed + TANK_ACCELERATION );

		else
			vecNewVelocity = gpGlobals->v_forward * 250;
	}


	else if ( m_pPlayer->pev->button & IN_BACK)
	{

		m_iTankmove |= PUSH_BACKWARD;
		m_iTankmove &= ~PUSH_FORWARD;		

		if ( iSens == 1 )
		{
			if ( flSpeed > TANK_DECCELERATION * 2 )
				vecNewVelocity = gpGlobals->v_forward * ( flSpeed - TANK_DECCELERATION );
			else
				vecNewVelocity = Vector ( 0,0,0 );
		}

		else if ( flSpeed < 150 )
			vecNewVelocity = gpGlobals->v_forward * - ( flSpeed + TANK_ACCELERATION );
		else
			vecNewVelocity = gpGlobals->v_forward * -150;
	}

	
	else
	{
		if ( flSpeed > 5 )
			vecNewVelocity = gpGlobals->v_forward * ( flSpeed - 1 ) * iSens;
		else
			vecNewVelocity = gpGlobals->v_forward * flSpeed * iSens;


		m_iTankmove &= ~PUSH_BACKWARD;
		m_iTankmove &= ~PUSH_FORWARD;
	}


	if ( iSens == 1)
	{
		m_iTankmove |= MOVE_FORWARD;
		m_iTankmove &= ~MOVE_BACKWARD;
	}
	else
	{
		m_iTankmove |= MOVE_BACKWARD;
		m_iTankmove &= ~MOVE_FORWARD;
	}



	//modification de la direction du tank

	if ( m_pPlayer->pev->button & IN_MOVELEFT )
		flNewAVelocity = TANK_ROT_SPEED;

	else if ( m_pPlayer->pev->button & IN_MOVERIGHT )
		flNewAVelocity = -TANK_ROT_SPEED;

	else
		flNewAVelocity = 0;


	// test de la position envisagée

	UTIL_MakeVectors ( pev->angles + Vector ( 0, flNewAVelocity / 10 , 0) );

	TraceResult	tr [4]/*1,tr2,tr3,tr4*/;
	Vector vecFrontLeft, vecFrontRight, vecBackLeft, vecBackRight;

	vecFrontLeft =	NEW_ORIGIN + gpGlobals->v_forward * DIST_FRONT_UP + gpGlobals->v_right * -DIST_SIDE + gpGlobals->v_up * DIST_TOP;
	vecFrontRight = NEW_ORIGIN + gpGlobals->v_forward * DIST_FRONT_UP + gpGlobals->v_right * DIST_SIDE + gpGlobals->v_up * DIST_TOP;
	vecBackLeft =	NEW_ORIGIN + gpGlobals->v_forward * DIST_BACK_UP + gpGlobals->v_right * -DIST_SIDE + gpGlobals->v_up * DIST_TOP;
	vecBackRight =	NEW_ORIGIN + gpGlobals->v_forward * DIST_BACK_UP + gpGlobals->v_right * DIST_SIDE + gpGlobals->v_up * DIST_TOP;
					
	UTIL_TraceLine (vecFrontLeft, vecFrontRight,ignore_monsters, ENT(m_pTankBSP->pev), &tr[0]);
	UTIL_TraceLine (vecFrontRight, vecBackRight,ignore_monsters, ENT(m_pTankBSP->pev), &tr[1]);
	UTIL_TraceLine (vecBackRight, vecBackLeft,	ignore_monsters, ENT(m_pTankBSP->pev), &tr[2]);
	UTIL_TraceLine (vecBackLeft, vecFrontLeft,	ignore_monsters, ENT(m_pTankBSP->pev), &tr[3]);


	//pas de collision - application de la nouvelle position

	if ( tr[0].vecEndPos == vecFrontRight && tr[1].vecEndPos == vecBackRight && tr[2].vecEndPos == vecBackLeft && tr[3].vecEndPos == vecFrontLeft )
	{
		StudioFrameAdvance ( 0.1 );

		pev->velocity = vecNewVelocity;
		pev->avelocity = Vector ( 0, flNewAVelocity, 0 );

		m_pCam->m_vecTourelleAngle = pev->v_angle;
		m_pCam->m_flNextFrameTime = pev->nextthink;

		pev->v_angle.y = flNextVAngleY;
		pev->v_angle.x = flNextVAngleX;


		m_pTankBSP->pev->velocity = (( pev->origin + vecNewVelocity * 10 ) - m_pTankBSP->pev-> origin ) / 10 ;
		m_pTankBSP->pev->avelocity = (( pev->angles + Vector ( 0, flNewAVelocity * 10, 0 ) - m_pTankBSP->pev->angles )) / 10;
		// pour combler la différence de vitesse entre le bsp et le mdl

	}

	//collision - arret du tank

	else
	{
		pev->velocity = pev->avelocity = Vector (0,0,0);
		m_pTankBSP->pev->velocity = ( pev->origin - m_pTankBSP->pev-> origin ) / 10 ;
		m_pTankBSP->pev->avelocity = ( pev->angles - m_pTankBSP->pev->angles ) / 10;

		if ( flSpeed > 50 )	// choc violent
		{
			EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, CHOC_SOUND, 0.9, ATTN_NORM, 0, 60 );

		}
	}


	// application des dommages

	vecFrontLeft = vecFrontLeft + Vector ( 0, 0, 10 - DIST_TOP );
	vecFrontRight = vecFrontRight + Vector ( 0, 0, 10 - DIST_TOP );
	vecBackRight = vecBackRight + Vector ( 0, 0, 10 - DIST_TOP );
	vecBackLeft = vecBackLeft + Vector ( 0, 0, 10 - DIST_TOP );

	UTIL_TraceLine (vecFrontLeft, vecFrontRight,dont_ignore_monsters, ENT(m_pTankBSP->pev), &tr[0]);
	UTIL_TraceLine (vecFrontRight, vecBackRight,dont_ignore_monsters, ENT(m_pTankBSP->pev), &tr[1]);
	UTIL_TraceLine (vecBackRight, vecBackLeft,	dont_ignore_monsters, ENT(m_pTankBSP->pev), &tr[2]);
	UTIL_TraceLine (vecBackLeft, vecFrontLeft,	dont_ignore_monsters, ENT(m_pTankBSP->pev), &tr[3]);

	CBaseEntity *pEntity = NULL;

	for ( int i = 0 ; i < 4 ; i ++ )
	{
		if ( tr [ i ].pHit != NULL )
		{
			pEntity =  CBaseEntity :: Instance ( tr [ i ].pHit );

			if ( pEntity != NULL && pEntity->pev->takedamage  )
			{
				float fDamage;

				if ( FClassnameIs ( tr[i].pHit, "func_breakable" ) )
				{
					fDamage =  pEntity->pev->health;
				}
				else
				{
					fDamage = pev->velocity.Length() * 1.5 + 20;
				}

				pEntity->TakeDamage ( pev, pev , fDamage , DMG_CRUSH );
			}
		}
	}

	//rectification de la position de la camera

	vecCamAim = UpdateCam();

	if ( m_pCam->pev->origin != vecCamAim )
		m_pCam->pev->velocity = ( vecCamAim - m_pCam->pev->origin ) * 10;

	UpdateCamAngle ( vecCamAim, NEXTTHINK_TIME );



	//tir de la tourelle

	if ( ( m_pPlayer->pev->button & IN_ATTACK ) && ( gpGlobals->time > m_flLastAttack1 + TANK_REFIRE_DELAY ) )
	{
		Fire ( bCanon );
		bCanon = bCanon == TRUE ? FALSE : TRUE;

		EMIT_SOUND(ENT(pev), CHAN_AUTO, TIR_SOUND, 1, ATTN_NORM);
		m_flLastAttack1 = gpGlobals->time;

		m_pCam->pev->avelocity.x -= 45;

	}

	//tir de la mitrailleuse

	if ( m_pPlayer->pev->button & IN_ATTACK2 )
	{
		Vector posGun, dirGun;
		GetAttachment( 3, posGun, Vector ( 0, 0, 0 ) );
		UTIL_MakeVectorsPrivate( TourelleAngle(), dirGun, NULL, NULL );
		FireBullets( 1, posGun, dirGun, VECTOR_CONE_5DEGREES, 8192, BULLET_MONSTER_12MM );

		EMIT_SOUND(ENT(pev), CHAN_WEAPON, MITRAILLEUSE_SOUND, 1, ATTN_NORM);

		if ( !FStrEq(STRING(gpGlobals->mapname), "l3m10") && !FStrEq(STRING(gpGlobals->mapname), "l3m12")  && !FStrEq(STRING(gpGlobals->mapname), "l3m14")  )
		{			
			CSprite *pSprite = CSprite::SpriteCreate( SPRITE_MUZ, posGun, TRUE );
			pSprite->AnimateAndDie( 15 );
			pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation );
			pSprite->SetAttachment( edict(), 4 );
			pSprite->SetScale( SPRITE_MUZ_SCALE );
		}


	}



	//sond du tank

	UpdateSound ();

	CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 2.5, 150, NEXTTHINK_TIME );
	CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, 2000, 0.5 );



}
Ejemplo n.º 25
0
//-----------------------------------------------------------------------------
// Purpose: Update the fire and its children
//-----------------------------------------------------------------------------
void CFire::Update( float simTime )
{
	VPROF_FIRE( "CFire::Update" );

	if ( m_flFuel != 0 )
	{
		m_flFuel -= simTime;
		if ( m_flFuel <= 0 )
		{
			GoOutInSeconds( 1 );
			return;
		}
	}

	float strength = m_flHeatLevel / FIRE_MAX_HEAT_LEVEL;
	if ( m_flHeatLevel != m_flLastHeatLevel )
	{
		m_flLastHeatLevel = m_flHeatLevel;
		// Make the effect the appropriate size given the heat level
		m_hEffect->Scale( strength, 0.5f );		
	}
	// add heat to myself (grow)
	float addedHeat = (m_flAttackTime > 0) ? m_flMaxHeat / m_flAttackTime : m_flMaxHeat;
	addedHeat *= simTime * fire_growthrate.GetFloat();
	AddHeat( addedHeat, true );

	// add heat to nearby fires
	float outputHeat = strength * m_flHeatLevel;

	Vector fireMins;
	Vector fireMaxs;
	Vector fireEntityDamageMins;
	Vector fireEntityDamageMaxs;

	GetFireDimensions( &fireMins, &fireMaxs );

	if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) // if set to 1.0, optimizer will remove this code
	{
		fireEntityDamageMins = fireMins / FIRE_SPREAD_DAMAGE_MULTIPLIER;
		fireEntityDamageMaxs = fireMaxs / FIRE_SPREAD_DAMAGE_MULTIPLIER;
	}

	//NDebugOverlay::Box( GetAbsOrigin(), fireMins, fireMaxs, 255, 255, 255, 0, fire_dmginterval.GetFloat() );
	fireMins += GetAbsOrigin();
	fireMaxs += GetAbsOrigin();

	if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 )
	{
		fireEntityDamageMins += GetAbsOrigin();
		fireEntityDamageMaxs += GetAbsOrigin();
	}

	CBaseEntity *pNearby[256];
	CFire *pFires[16];
	int nearbyCount = UTIL_EntitiesInBox( pNearby, ARRAYSIZE(pNearby), fireMins, fireMaxs, 0 );
	int fireCount = 0;
	int i;

	// is it time to do damage?
	bool damage = false;
	int outputDamage = 0;
	if ( m_flDamageTime <= gpGlobals->curtime )
	{
		m_flDamageTime = gpGlobals->curtime + fire_dmginterval.GetFloat();
		outputDamage = (fire_dmgbase.GetFloat() + outputHeat * fire_dmgscale.GetFloat() * m_flDamageScale) * fire_dmginterval.GetFloat();
		if ( outputDamage )
		{
			damage = true;
		}
	}
	int damageFlags = (m_nFireType == FIRE_NATURAL) ? DMG_BURN : DMG_PLASMA;
	for ( i = 0; i < nearbyCount; i++ )
	{
		CBaseEntity *pOther = pNearby[i];

		if ( pOther == this )
		{
			continue;
		}
		else if ( FClassnameIs( pOther, "env_fire" ) )
		{
			if ( fireCount < ARRAYSIZE(pFires) )
			{
				pFires[fireCount] = (CFire *)pOther;
				fireCount++;
			}
			continue;
		}
		else if ( pOther->m_takedamage == DAMAGE_NO )
		{
			pNearby[i] = NULL;
		}
		else if ( damage )
		{
			bool bDoDamage;

			if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 && !pOther->IsPlayer() ) // if set to 1.0, optimizer will remove this code
			{
				Vector otherMins, otherMaxs;
				pOther->CollisionProp()->WorldSpaceAABB( &otherMins, &otherMaxs );
				bDoDamage = IsBoxIntersectingBox( otherMins, otherMaxs, 
												  fireEntityDamageMins, fireEntityDamageMaxs );

			}
			else
				bDoDamage = true;

			if ( bDoDamage )
			{
				// Make sure can actually see entity (don't damage through walls)
				trace_t tr;
				UTIL_TraceLine( this->WorldSpaceCenter(), pOther->WorldSpaceCenter(), MASK_FIRE_SOLID, pOther, COLLISION_GROUP_NONE, &tr );

				if (tr.fraction == 1.0 && !tr.startsolid)
				{
					pOther->TakeDamage( CTakeDamageInfo( this, this, outputDamage, damageFlags ) );
				}
			}
		}
	}

	outputHeat *= fire_heatscale.GetFloat() * simTime;

	if ( fireCount > 0 )
	{
		outputHeat /= fireCount;
		for ( i = 0; i < fireCount; i++ )
		{
			pFires[i]->AddHeat( outputHeat, false );
		}
	}
}
Ejemplo n.º 26
0
void CBaseDoor::Blocked( CBaseEntity *pOther )
{
    edict_t	*pentTarget = NULL;
    CBaseDoor	*pDoor		= NULL;


    // Hurt the blocker a little.
    if ( pev->dmg )
        pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH );

    // if a door has a negative wait, it would never come back if blocked,
    // so let it just squash the object to death real fast

    if (m_flWait >= 0)
    {
        if (m_toggle_state == TS_GOING_DOWN)
        {
            DoorGoUp();
        }
        else
        {
            DoorGoDown();
        }
    }

    // Block all door pieces with the same targetname here.
    if ( !FStringNull ( pev->targetname ) )
    {
        for (;;)
        {
            pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname));

            if ( VARS( pentTarget ) != pev )
            {
                if (FNullEnt(pentTarget))
                    break;

                if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) )
                {

                    pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) );

                    if ( pDoor->m_flWait >= 0)
                    {
                        if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity)
                        {
                            // this is the most hacked, evil, bastardized thing I've ever seen. kjb
                            if ( FClassnameIs ( pentTarget, "func_door" ) )
                            {   // set origin to realign normal doors
                                pDoor->pev->origin = pev->origin;
                                pDoor->pev->velocity = g_vecZero;// stop!
                            }
                            else
                            {   // set angles to realign rotating doors
                                pDoor->pev->angles = pev->angles;
                                pDoor->pev->avelocity = g_vecZero;
                            }
                        }

                        if ( pDoor->m_toggle_state == TS_GOING_DOWN)
                            pDoor->DoorGoUp();
                        else
                            pDoor->DoorGoDown();
                    }
                }
            }
        }
    }
}
//-----------------------------------------------------------------------------
// Purpose: 
//
//
// Output : 
//-----------------------------------------------------------------------------
CBaseEntity *CNPC_RollerDozer::FindDebris( void )
{
	if( !m_pHintNode )
	{
		// Detect rubbish near a hint node.
		CAI_Hint* pHintNode = CAI_Hint::FindHint( this, HINT_ROLLER_CLEANUP_POINT, 0, 1024 ); 


		if( pHintNode)
		{
			// Search around the hint node for debris that should be cleared.
			Vector vecHintNodeOrigin;
			
			// Get hint node position
			vecHintNodeOrigin;
			pHintNode->GetPosition(this,&vecHintNodeOrigin);

			CBaseEntity *pList[ 16 ];
			Vector vecDeltaUp( 200, 200, 64 );
			Vector vecDeltaDown( 200, 200, 10 );
			int i;
			IPhysicsObject	*pPhysObj;

			int count = UTIL_EntitiesInBox( pList, 16, vecHintNodeOrigin - vecDeltaDown, vecHintNodeOrigin + vecDeltaUp, 0 );
			
			float m_flHeaviestMass = 0;
			CBaseEntity *pHeaviest = NULL;
			
			for( i = 0 ; i < count ; i++ )
			{
				pPhysObj = pList[ i ]->VPhysicsGetObject();

				if( !pPhysObj || FClassnameIs( pList[ i ], "npc_rollerdozer" ) )
				{
					// Only consider physics objects. Exclude rollers.
					continue;
				}

				if( pPhysObj->GetMass() <= 400 )
				{
					if( pPhysObj->GetMass() > m_flHeaviestMass )
					{
						m_flHeaviestMass = pPhysObj->GetMass();
						pHeaviest = pList[ i ];
					}

/*
					// Report to the cleanup point and doze this piece of debris away.
					SetCondition( COND_ROLLERDOZER_FOUND_DEBRIS );
					m_vecCleanupPoint = vecHintNodeOrigin;


					return pList[ i ];
*/
				}
			}

			if( pHeaviest )
			{
				SetCondition( COND_ROLLERDOZER_FOUND_DEBRIS );
				//NDebugOverlay::Line( GetLocalOrigin(), pHeaviest->GetLocalOrigin(), 255,255,0, true, 3 );
				m_vecCleanupPoint = vecHintNodeOrigin;
				return pHeaviest;
			}
		}
	}

	return NULL;
}
Ejemplo n.º 28
0
void CCrossbowBolt::BoltTouch( CBaseEntity *pOther )
{
	SetTouch( NULL );
	SetThink( NULL );

	if (pOther->pev->takedamage)
	{
		TraceResult tr = UTIL_GetGlobalTrace( );
		entvars_t	*pevOwner;

		pevOwner = VARS( pev->owner );

		// UNDONE: this needs to call TraceAttack instead
		g_MultiDamage.Clear( );

		if ( pOther->IsPlayer() )
		{
			pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); 
		}
		else
		{
			pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); 
		}

		g_MultiDamage.ApplyMultiDamage( pev, pevOwner );

		pev->velocity = Vector( 0, 0, 0 );
		// play body "thwack" sound
		switch( RANDOM_LONG(0,1) )
		{
		case 0:
			EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break;
		case 1:
			EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break;
		}

		if ( !g_pGameRules->IsMultiplayer() )
		{
			Killed( pev, GIB_NEVER );
		}
	}
	else
	{
		EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7));

		SetThink( &CCrossbowBolt::SUB_Remove );
		pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit.

		if ( FClassnameIs( pOther->pev, "worldspawn" ) )
		{
			// if what we hit is static architecture, can stay around for a while.
			Vector vecDir = pev->velocity.Normalize( );
			UTIL_SetOrigin( pev, pev->origin - vecDir * 12 );
			pev->angles = UTIL_VecToAngles( vecDir );
			pev->solid = SOLID_NOT;
			pev->movetype = MOVETYPE_FLY;
			pev->velocity = Vector( 0, 0, 0 );
			pev->avelocity.z = 0;
			pev->angles.z = RANDOM_LONG(0,360);
			pev->nextthink = gpGlobals->time + 10.0;
		}

		if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
		{
			UTIL_Sparks( pev->origin );
		}
	}

	if ( g_pGameRules->IsMultiplayer() )
	{
		SetThink( &CCrossbowBolt::ExplodeThink );
		pev->nextthink = gpGlobals->time + 0.1;
	}
}
//=========================================================
// GetSchedule 
//=========================================================
int CNPC_Bullsquid::SelectSchedule( void )
{
	switch	( m_NPCState )
	{
	case NPC_STATE_IDLE:
		{
			return SCHED_PATROL_WALK_LOOP;
		}
		break;
	case NPC_STATE_ALERT:
		{
			if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
			{
				return SCHED_SQUID_HURTHOP;
			}

			if ( HasCondition( COND_SQUID_SMELL_FOOD ) )
			{
				CSound		*pSound;

				pSound = GetBestScent();
				
				if ( pSound && (!FInViewCone( pSound->GetSoundOrigin() ) || !FVisible( pSound->GetSoundOrigin() )) )
				{
					// scent is behind or occluded
					return SCHED_SQUID_SNIFF_AND_EAT;
				}

				// food is right out in the open. Just go get it.
				return SCHED_SQUID_EAT;
			}

			if ( HasCondition( COND_SMELL ) )
			{
				// there's something stinky. 
				CSound		*pSound;

				pSound = GetBestScent();
				if ( pSound )
					return SCHED_SQUID_WALLOW;
			}

			return SCHED_PATROL_WALK_LOOP;

			break;
		}
	case NPC_STATE_COMBAT:
		{
// dead enemy
			if ( HasCondition( COND_ENEMY_DEAD ) )
			{
				// call base class, all code to handle dead enemies is centralized there.
				return BaseClass::SelectSchedule();
			}

			if ( HasCondition( COND_NEW_ENEMY ) )
			{
				if ( m_fCanThreatDisplay && IRelationType( GetEnemy() ) == D_HT && FClassnameIs( GetEnemy(), "monster_headcrab" ) )
				{
					// this means squid sees a headcrab!
					m_fCanThreatDisplay = FALSE;// only do the headcrab dance once per lifetime.
					return SCHED_SQUID_SEECRAB;
				}
				else
				{
					return SCHED_WAKE_ANGRY;
				}
			}

			if ( HasCondition( COND_SQUID_SMELL_FOOD ) )
			{
				CSound		*pSound;

				pSound = GetBestScent();
				
				if ( pSound && (!FInViewCone( pSound->GetSoundOrigin() ) || !FVisible( pSound->GetSoundOrigin() )) )
				{
					// scent is behind or occluded
					return SCHED_SQUID_SNIFF_AND_EAT;
				}

				// food is right out in the open. Just go get it.
				return SCHED_SQUID_EAT;
			}

			if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
			{
				return SCHED_RANGE_ATTACK1;
			}

			if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) )
			{
				return SCHED_MELEE_ATTACK1;
			}

			if ( HasCondition( COND_CAN_MELEE_ATTACK2 ) )
			{
				return SCHED_MELEE_ATTACK2;
			}
			
			return SCHED_CHASE_ENEMY;

			break;
		}
	}

	return BaseClass::SelectSchedule();
}
Ejemplo n.º 30
0
/*
AddToFullPack

Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise

state is the server maintained copy of the state info that is transmitted to the client
a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc.
e and ent are the entity that is being added to the update, if 1 is returned
host is the player's edict of the player whom we are sending the update to
player is 1 if the ent/e is a player and 0 otherwise
pSet is either the PAS or PVS that we previous set up.  We can use it to ask the engine to filter the entity against the PAS or PVS.
we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to.  Caching the value is valid in that case, but still only for the current frame
*/
int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet )
{
	int					i;

	// don't send if flagged for NODRAW and it's not the host getting the message
	if ( ( ent->v.effects == EF_NODRAW ) &&
		 ( ent != host ) )
		return 0;

	// Ignore ents without valid / visible models
	if ( !ent->v.modelindex || !STRING( ent->v.model ) )
		return 0;

	// Don't send spectators to other players
	if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) )
	{
		return 0;
	}

	// Ignore if not the host and not touching a PVS/PAS leaf
	// If pSet is NULL, then the test will always succeed and the entity will be added to the update
	if ( ent != host )
	{
		// modif de Julien
		if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) && !FClassnameIs ( ent, "info_tank_camera") )
		{
			return 0;
		}
	}

	// Don't send entity to local client if the client says it's predicting the entity itself.
	if ( ent->v.flags & FL_SKIPLOCALHOST )
	{
		if ( ( hostflags & 1 ) && ( ent->v.owner == host ) )
			return 0;
	}
	

	if ( host->v.groupinfo )
	{
		UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND );

		// Should always be set, of course
		if ( ent->v.groupinfo )
		{
			if ( g_groupop == GROUP_OP_AND )
			{
				if ( !(ent->v.groupinfo & host->v.groupinfo ) )
					return 0;
			}
			else if ( g_groupop == GROUP_OP_NAND )
			{
				if ( ent->v.groupinfo & host->v.groupinfo )
					return 0;
			}
		}

		UTIL_UnsetGroupTrace();
	}

	
	memset( state, 0, sizeof( *state ) );

	// Assign index so we can track this entity from frame to frame and
	//  delta from it.
	state->number	  = e;
	state->entityType = ENTITY_NORMAL;
	
	// Flag custom entities.
	if ( ent->v.flags & FL_CUSTOMENTITY )
	{
		state->entityType = ENTITY_BEAM;
	}

	// 
	// Copy state data
	//

	// Round animtime to nearest millisecond
	state->animtime   = (int)(1000.0 * ent->v.animtime ) / 1000.0;

	memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) );
	memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) );
	memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) );
	memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) );

	memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) );
	memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) );

	state->impacttime = ent->v.impacttime;
	state->starttime = ent->v.starttime;

	state->modelindex = ent->v.modelindex;
		
	state->frame      = ent->v.frame;

	state->skin       = ent->v.skin;
	state->effects    = ent->v.effects;

	// This non-player entity is being moved by the game .dll and not the physics simulation system
	//  make sure that we interpolate it's position on the client if it moves
	if ( !player &&
		 ent->v.animtime &&
		 ent->v.velocity[ 0 ] == 0 && 
		 ent->v.velocity[ 1 ] == 0 && 
		 ent->v.velocity[ 2 ] == 0 )
	{
		state->eflags |= EFLAG_SLERP;
	}

	state->scale	  = ent->v.scale;
	state->solid	  = ent->v.solid;
	state->colormap   = ent->v.colormap;
	state->movetype   = ent->v.movetype;
	state->sequence   = ent->v.sequence;
	state->framerate  = ent->v.framerate;
	state->body       = ent->v.body;

	for (i = 0; i < 4; i++)
	{
		state->controller[i] = ent->v.controller[i];
	}

	for (i = 0; i < 2; i++)
	{
		state->blending[i]   = ent->v.blending[i];
	}

	state->rendermode    = ent->v.rendermode;
	state->renderamt     = ent->v.renderamt; 
	state->renderfx      = ent->v.renderfx;
	state->rendercolor.r = ent->v.rendercolor[0];
	state->rendercolor.g = ent->v.rendercolor[1];
	state->rendercolor.b = ent->v.rendercolor[2];

	state->aiment = 0;
	if ( ent->v.aiment )
	{
		state->aiment = ENTINDEX( ent->v.aiment );
	}

	state->owner = 0;
	if ( ent->v.owner )
	{
		int owner = ENTINDEX( ent->v.owner );
		
		// Only care if owned by a player
		if ( owner >= 1 && owner <= gpGlobals->maxClients )
		{
			state->owner = owner;	
		}
	}

	// HACK:  Somewhat...
	// Class is overridden for non-players to signify a breakable glass object ( sort of a class? )
	if ( !player )
	{
		state->playerclass  = ent->v.playerclass;
	}

	// Special stuff for players only
	if ( player )
	{
		memcpy( state->basevelocity, ent->v.basevelocity, 3 * sizeof( float ) );

		state->weaponmodel  = MODEL_INDEX( STRING( ent->v.weaponmodel ) );
		state->gaitsequence = ent->v.gaitsequence;
		state->spectator = ent->v.flags & FL_SPECTATOR;
		state->friction     = ent->v.friction;

		state->gravity      = ent->v.gravity;
//		state->team			= ent->v.team;
//		state->playerclass  = ent->v.playerclass;
		state->usehull      = ( ent->v.flags & FL_DUCKING ) ? 1 : 0;
		state->health		= ent->v.health;
	}



	return 1;
}