View Single Post
Re: Finding place of grenade explosion
Old
  (#2)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Warning Re: Finding place of grenade explosion - 07-07-2010

EDIT: Function TraceThrownGrenadeToss() is a bit rewritten.
REMOVED BLOCK:
Code:
if (UTIL_PointContents (pseudoGrenadeEntityVariablesExtended.origin) == CONTENTS_SOLID)
		return;	// grenade is trapped in another solid
ADDED:
Code:
pseudoGrenadeEntityVariablesExtended.flags |= FL_KILLME;
if (!IsInWorld (grenade)) - to check whether grenade will be removed.
ADDED BLOCK:
Code:
if (traceResult.fAllSolid)
		{
			// grenade is trapped in another solid
			pseudoGrenadeEntityVariablesExtended.velocity = vec3_origin;

			pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;

			pseudoGrenadeEntityVariables = pseudoGrenadeEntityVariablesExtended;

			// Restore touched breakables solid types
			for (unsigned char index (0u); index < touchedBreakables.size (); ++index)
				touchedBreakables[index]->v.solid = SOLID_BSP;

			for (unsigned char index (0u); index < touchedPushables.size (); ++index)
				touchedPushables[index]->v.solid = SOLID_TRIGGER;

			return;
		}
NOTE: Function does not always returns right explosion origin vector, if grenade is collided with player!!!

Full function code:
Code:
void TraceThrownGrenadeToss (const edict_t *const grenade, PseudoGrenadeEntityVariables_t &pseudoGrenadeEntityVariables)
{
	struct PseudoGrenadeEntityVariablesExtended_t : PseudoGrenadeEntityVariables_t
	{
		Vector         velocity;		// current movement direction
		Vector         basevelocity;	// if standing on conveyor, e.g.
		int            watertype;
		edict_t       *groundentity;	// if standing on a entity, the pointer to that entity
		float          friction;		// inverse elasticity of 'MOVETYPE_BOUNCE'
		float          nextthink;		// Time next call BaseEntity::Think() function.

		unsigned char  numberFloorHits;
	} pseudoGrenadeEntityVariablesExtended;

	pseudoGrenadeEntityVariablesExtended.origin = grenade->v.origin;
	pseudoGrenadeEntityVariablesExtended.waterlevel = grenade->v.waterlevel;
	pseudoGrenadeEntityVariablesExtended.flags = grenade->v.flags;
	pseudoGrenadeEntityVariablesExtended.velocity = grenade->v.velocity;
	pseudoGrenadeEntityVariablesExtended.basevelocity = grenade->v.basevelocity;
	pseudoGrenadeEntityVariablesExtended.watertype = grenade->v.watertype;
	pseudoGrenadeEntityVariablesExtended.groundentity = grenade->v.groundentity;
	pseudoGrenadeEntityVariablesExtended.friction = grenade->v.friction;
	pseudoGrenadeEntityVariablesExtended.nextthink = grenade->v.nextthink;
	pseudoGrenadeEntityVariablesExtended.numberFloorHits = 0u;

	const unsigned char maximumFloorHits (10u);

	pseudoGrenadeEntityVariables = pseudoGrenadeEntityVariablesExtended;

	TraceResult traceResult;
	const float pseudoFrameTimeInterval (/*0.05f*/gpGlobals->frameTime);	// Use your own bigger value if you want to reduce CPU work....
	float pseudoTime (gpGlobals->time);
	Vector to;
	const float gravityAdjust (grenade->v.gravity * sv_gravity->value * pseudoFrameTimeInterval);
	vector <edict_t *> touchedBreakables;
	vector <edict_t *> touchedPushables;

	// Run pseudo frames....
	do
	{
		pseudoGrenadeEntityVariablesExtended.basevelocity = pseudoGrenadeEntityVariablesExtended.groundentity != NULL && (pseudoGrenadeEntityVariablesExtended.groundentity->v.flags & FL_CONVEYOR) ? pseudoGrenadeEntityVariablesExtended.groundentity->v.speed * pseudoGrenadeEntityVariablesExtended.groundentity->v.movedir : vec3_origin;

		for (edict_t *pushable (FIND_ENTITY_BY_CLASSNAME (NULL, "trigger_push")); !FNullEnt (pushable); pushable = FIND_ENTITY_BY_CLASSNAME (pushable, "trigger_push"))
		{
			if (pushable->v.solid == SOLID_NOT || !IsPointInsideBoundingBox (pseudoGrenadeEntityVariablesExtended.origin, pushable->v.absmin, pushable->v.absmax))
				continue;

			// Instant trigger, just transfer velocity and remove
			if (pushable->v.spawnflags & SF_TRIG_PUSH_ONCE)
			{
				pseudoGrenadeEntityVariablesExtended.velocity += pushable->v.speed * pushable->v.movedir;

				if (pseudoGrenadeEntityVariablesExtended.velocity.z > 0.0f)
					pseudoGrenadeEntityVariablesExtended.flags &= ~FL_ONGROUND;

				pushable->v.solid = SOLID_NOT;

				touchedPushables.push_back (pushable);
			}
			else
			{	// Push field, transfer to base velocity
				Vector vecPush (pushable->v.speed * pushable->v.movedir);

				if (pseudoGrenadeEntityVariablesExtended.flags & FL_BASEVELOCITY)
					vecPush += pseudoGrenadeEntityVariablesExtended.basevelocity;

				pseudoGrenadeEntityVariablesExtended.basevelocity = vecPush;

				pseudoGrenadeEntityVariablesExtended.flags |= FL_BASEVELOCITY;
			}
		}

		pseudoGrenadeEntityVariablesExtended.waterlevel = 0;
		pseudoGrenadeEntityVariablesExtended.watertype = CONTENTS_EMPTY;
		const int cont (UTIL_PointContents (pseudoGrenadeEntityVariablesExtended.origin));

		if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT)
		{
			pseudoGrenadeEntityVariablesExtended.watertype = cont;
			pseudoGrenadeEntityVariablesExtended.waterlevel = 3;

			if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
			{
				static const Vector current_table[] =
				{
					Vector ( 1.0f,  0.0f,  0.0f),
					Vector ( 0.0f,  1.0f,  0.0f),
					Vector (-1.0f,  0.0f,  0.0f),
					Vector ( 0.0f, -1.0f,  0.0f),
					Vector ( 0.0f,  0.0f,  1.0f),
					Vector ( 0.0f,  0.0f, -1.0f)
				};

				pseudoGrenadeEntityVariablesExtended.basevelocity += pseudoGrenadeEntityVariablesExtended.waterlevel * 50.0f * current_table[CONTENTS_CURRENT_0 - cont];
			}
		}

	// regular thinking
		{
			float thinkTime (pseudoGrenadeEntityVariablesExtended.nextthink);

			if (thinkTime <= pseudoTime + pseudoFrameTimeInterval)
			{
				if
				(
					// check position
					pseudoGrenadeEntityVariablesExtended.origin.x >=  HalfMapSize ||
					pseudoGrenadeEntityVariablesExtended.origin.y >=  HalfMapSize ||
					pseudoGrenadeEntityVariablesExtended.origin.z >=  HalfMapSize ||
					pseudoGrenadeEntityVariablesExtended.origin.x <= -HalfMapSize ||
					pseudoGrenadeEntityVariablesExtended.origin.y <= -HalfMapSize ||
					pseudoGrenadeEntityVariablesExtended.origin.z <= -HalfMapSize ||
	
					// check speed
					pseudoGrenadeEntityVariablesExtended.velocity.x >=  2000.0f ||
					pseudoGrenadeEntityVariablesExtended.velocity.y >=  2000.0f ||
					pseudoGrenadeEntityVariablesExtended.velocity.z >=  2000.0f ||
					pseudoGrenadeEntityVariablesExtended.velocity.x <= -2000.0f ||
					pseudoGrenadeEntityVariablesExtended.velocity.y <= -2000.0f ||
					pseudoGrenadeEntityVariablesExtended.velocity.z <= -2000.0f
				)
				{
					pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;
					pseudoGrenadeEntityVariablesExtended.flags |= FL_KILLME;

					pseudoGrenadeEntityVariables = pseudoGrenadeEntityVariablesExtended;

					// Restore touched breakables solid types
					for (unsigned char index (0u); index < touchedBreakables.size (); ++index)
						touchedBreakables[index]->v.solid = SOLID_BSP;

					for (unsigned char index (0u); index < touchedPushables.size (); ++index)
						touchedPushables[index]->v.solid = SOLID_TRIGGER;

					return;
				}

				if (thinkTime < pseudoTime)
					thinkTime = pseudoTime;	// don't let things stay in the past.
											// it is possible to start that way
											// by a trigger with a local time.

				pseudoTime = thinkTime;

				pseudoGrenadeEntityVariablesExtended.nextthink = pseudoTime + 0.1f;

				if (IsSmokeGrenade (grenade) && (pseudoGrenadeEntityVariablesExtended.flags & FL_ONGROUND))
					pseudoGrenadeEntityVariablesExtended.velocity *= 0.949f;//0.949999988079071f - value from decompiled swds.dll sources, I think it's would be 0.949f - IDA sometimes wrong, ex: org 0.8 == decompiled 0.800000011920929 - may be I wrong....

				if (pseudoGrenadeEntityVariablesExtended.waterlevel > 0u)
					pseudoGrenadeEntityVariablesExtended.velocity *= 0.5f;
			}
		}

		if (pseudoGrenadeEntityVariablesExtended.velocity.z > 0.0f || pseudoGrenadeEntityVariablesExtended.groundentity == NULL || (pseudoGrenadeEntityVariablesExtended.groundentity->v.flags & FL_CONVEYOR))
			pseudoGrenadeEntityVariablesExtended.flags &= ~FL_ONGROUND;

// if onground, return without moving
		if ((pseudoGrenadeEntityVariablesExtended.flags & FL_ONGROUND) && VectorCompare (pseudoGrenadeEntityVariablesExtended.origin, vec3_origin) && VectorCompare (pseudoGrenadeEntityVariablesExtended.basevelocity, vec3_origin))
		{
			pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;

			continue;
		}

		pseudoGrenadeEntityVariablesExtended.velocity.z -= gravityAdjust;
		pseudoGrenadeEntityVariablesExtended.velocity.z += pseudoGrenadeEntityVariablesExtended.basevelocity.z * pseudoFrameTimeInterval;

		pseudoGrenadeEntityVariablesExtended.basevelocity.z = 0.0f;

// move origin
	// Base velocity is not properly accounted for since this entity will move again after the bounce without taking it into account
		to = pseudoGrenadeEntityVariablesExtended.origin + (pseudoGrenadeEntityVariablesExtended.velocity + pseudoGrenadeEntityVariablesExtended.basevelocity) * pseudoFrameTimeInterval;

		UTIL_TraceHull (pseudoGrenadeEntityVariablesExtended.origin, to, dont_ignore_monsters, point_hull, grenade->v.owner, &traceResult);	/// @note Use TraceHull() function instead of TraceLine() as TraceLine() returns worldspawn entity stored in pHit even if flFraction == 1 !!!!

		if (traceResult.flFraction > 0.0f)
			pseudoGrenadeEntityVariablesExtended.origin = traceResult.vecEndPos;

		if (traceResult.pHit != NULL)
		{
			if (FClassnameIs (traceResult.pHit, "func_breakable") && traceResult.pHit->v.rendermode != kRenderNormal)
			{
				pseudoGrenadeEntityVariablesExtended.velocity *= -2.0f;

				traceResult.pHit->v.solid = SOLID_NOT;

				touchedBreakables.push_back (traceResult.pHit);
			}
			else
			{
				if (pseudoGrenadeEntityVariablesExtended.flags & FL_ONGROUND)
				{
					// add a bit of static friction
					pseudoGrenadeEntityVariablesExtended.velocity *= 0.8f;
				}
				else
				{
					if (pseudoGrenadeEntityVariablesExtended.numberFloorHits >= maximumFloorHits)
					{
						pseudoGrenadeEntityVariablesExtended.groundentity = g_engfuncs.pfnPEntityOfEntIndex (0u);
						pseudoGrenadeEntityVariablesExtended.flags |= FL_ONGROUND;
						pseudoGrenadeEntityVariablesExtended.velocity = vec3_origin;
					}

					++pseudoGrenadeEntityVariablesExtended.numberFloorHits;
				}
			}
		}

		if (traceResult.fAllSolid)
		{
			// grenade is trapped in another solid
			pseudoGrenadeEntityVariablesExtended.velocity = vec3_origin;

			pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;

			pseudoGrenadeEntityVariables = pseudoGrenadeEntityVariablesExtended;

			// Restore touched breakables solid types
			for (unsigned char index (0u); index < touchedBreakables.size (); ++index)
				touchedBreakables[index]->v.solid = SOLID_BSP;

			for (unsigned char index (0u); index < touchedPushables.size (); ++index)
				touchedPushables[index]->v.solid = SOLID_TRIGGER;

			return;
		}

		if (traceResult.flFraction < 1.0f)
		{
			ClipVelocity (pseudoGrenadeEntityVariablesExtended.velocity, traceResult.vecPlaneNormal, pseudoGrenadeEntityVariablesExtended.velocity, 2.0f - grenade->v.friction);

			// stop if on ground
			if (traceResult.vecPlaneNormal.z > 0.7f)
			{
				Vector move (pseudoGrenadeEntityVariablesExtended.basevelocity + pseudoGrenadeEntityVariablesExtended.velocity);

				if (move.z < sv_gravity->value * pseudoFrameTimeInterval)
				{
					// we're rolling on the ground, add static friction.
					pseudoGrenadeEntityVariablesExtended.flags |= FL_ONGROUND;
					pseudoGrenadeEntityVariablesExtended.groundentity = traceResult.pHit;
					pseudoGrenadeEntityVariablesExtended.velocity.z = 0.0f;
				}

				if (move.GetLengthSquared () >= 30.0f * 30.0f)
				{
					const float scale ((1.0f - traceResult.flFraction) * pseudoFrameTimeInterval * 0.9f);

					move = scale * pseudoGrenadeEntityVariablesExtended.velocity + scale * pseudoGrenadeEntityVariablesExtended.basevelocity;
					to = pseudoGrenadeEntityVariablesExtended.origin + move;

					UTIL_TraceHull (pseudoGrenadeEntityVariablesExtended.origin, to, dont_ignore_monsters, point_hull, grenade->v.owner, &traceResult);	/// @note I use trace hull as this function returns NULL pointer of pHit when no collides, but trace line wasn't!!!

					if (traceResult.flFraction > 0.0f)
						pseudoGrenadeEntityVariablesExtended.origin = traceResult.vecEndPos;

					if (traceResult.pHit != NULL)
					{
						if (FClassnameIs (traceResult.pHit, "func_breakable") && traceResult.pHit->v.rendermode != kRenderNormal)
						{
							pseudoGrenadeEntityVariablesExtended.velocity *= -2.0f;

							traceResult.pHit->v.solid = SOLID_NOT;

							touchedBreakables.push_back (traceResult.pHit);
						}
						else
						{
							if (pseudoGrenadeEntityVariablesExtended.flags & FL_ONGROUND)
							{
								// add a bit of static friction
								pseudoGrenadeEntityVariablesExtended.velocity *= 0.8f;
							}
							else
							{
								if (pseudoGrenadeEntityVariablesExtended.numberFloorHits >= maximumFloorHits)
								{
									pseudoGrenadeEntityVariablesExtended.groundentity = g_engfuncs.pfnPEntityOfEntIndex (0u);
									pseudoGrenadeEntityVariablesExtended.flags |= FL_ONGROUND;
									pseudoGrenadeEntityVariablesExtended.velocity = vec3_origin;
								}

								++pseudoGrenadeEntityVariablesExtended.numberFloorHits;
							}
						}
					}
				}
				else
				{
					pseudoGrenadeEntityVariablesExtended.flags |= FL_ONGROUND;
					pseudoGrenadeEntityVariablesExtended.groundentity = traceResult.pHit;
					pseudoGrenadeEntityVariablesExtended.velocity = vec3_origin;
				}
			}
		}

		// check for in water
		const int cont (UTIL_PointContents (pseudoGrenadeEntityVariablesExtended.origin));

		if (pseudoGrenadeEntityVariablesExtended.watertype == 0)
		{	// just spawned here
			pseudoGrenadeEntityVariablesExtended.watertype = cont;
			pseudoGrenadeEntityVariablesExtended.waterlevel = 1;

			pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;

			continue;
		}

		if (cont > CONTENTS_WATER || cont <= CONTENTS_TRANSLUCENT)
		{
			pseudoGrenadeEntityVariablesExtended.watertype = CONTENTS_EMPTY;
			pseudoGrenadeEntityVariablesExtended.waterlevel = 0;
		}
		else
		{
			if (pseudoGrenadeEntityVariablesExtended.watertype == CONTENTS_EMPTY)
			{	// just crossed into water
				pseudoGrenadeEntityVariablesExtended.velocity.z *= 0.5f;
			}

			pseudoGrenadeEntityVariablesExtended.watertype = cont;
			pseudoGrenadeEntityVariablesExtended.waterlevel = 3;
		}

		pseudoGrenadeEntityVariablesExtended.flags &= ~FL_BASEVELOCITY;
	} while (IsSmokeGrenade (grenade) ? grenade->v.dmgtime > (pseudoTime += pseudoFrameTimeInterval) || !(pseudoGrenadeEntityVariablesExtended.flags & FL_ONGROUND) : grenade->v.dmgtime > (pseudoTime += pseudoFrameTimeInterval));

	pseudoGrenadeEntityVariables = pseudoGrenadeEntityVariablesExtended;

	// Restore touched breakables solid types
	for (unsigned char index (0u); index < touchedBreakables.size (); ++index)
		touchedBreakables[index]->v.solid = SOLID_BSP;

	for (unsigned char index (0u); index < touchedPushables.size (); ++index)
		touchedPushables[index]->v.solid = SOLID_TRIGGER;
}

Last edited by Immortal_BLG; 07-07-2010 at 07:41..
  
Reply With Quote