Initial commit.
This commit is contained in:
232
codemp/game/g_exphysics.c
Normal file
232
codemp/game/g_exphysics.c
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright (C) 2000-2002 Raven Software, Inc.
|
||||
//
|
||||
/*****************************************************************************
|
||||
* name: g_exphysics.c
|
||||
*
|
||||
* desc: Custom physics system (Expensive Physics)
|
||||
*
|
||||
* $Author: osman $
|
||||
* $Revision: 1.7 $
|
||||
*
|
||||
*****************************************************************************/
|
||||
#pragma warning(disable : 4701) //local variable may be used without having been initialized
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
#define MAX_GRAVITY_PULL 512
|
||||
|
||||
//Run physics on the object (purely origin-related) using custom epVelocity entity
|
||||
//state value. Origin smoothing on the client is expected to compensate for choppy
|
||||
//movement.
|
||||
void G_RunExPhys(gentity_t *ent, float gravity, float mass, float bounce, qboolean autoKill, int *g2Bolts, int numG2Bolts)
|
||||
{
|
||||
trace_t tr;
|
||||
vec3_t projectedOrigin;
|
||||
vec3_t vNorm;
|
||||
vec3_t ground;
|
||||
float velScaling = 0.1f;
|
||||
float vTotal = 0.0f;
|
||||
|
||||
assert(mass <= 1.0f && mass >= 0.01f);
|
||||
|
||||
if (gravity)
|
||||
{ //factor it in before we do anything.
|
||||
VectorCopy(ent->r.currentOrigin, ground);
|
||||
ground[2] -= 0.1f;
|
||||
|
||||
trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ground, ent->s.number, ent->clipmask);
|
||||
|
||||
if (tr.fraction == 1.0f)
|
||||
{
|
||||
ent->s.groundEntityNum = ENTITYNUM_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->s.groundEntityNum = tr.entityNum;
|
||||
}
|
||||
|
||||
if (ent->s.groundEntityNum == ENTITYNUM_NONE)
|
||||
{
|
||||
ent->epGravFactor += gravity;
|
||||
|
||||
if (ent->epGravFactor > MAX_GRAVITY_PULL)
|
||||
{ //cap it off if needed
|
||||
ent->epGravFactor = MAX_GRAVITY_PULL;
|
||||
}
|
||||
|
||||
ent->epVelocity[2] -= ent->epGravFactor;
|
||||
}
|
||||
else
|
||||
{ //if we're sitting on something then reset the gravity factor.
|
||||
ent->epGravFactor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ent->epVelocity[0] && !ent->epVelocity[1] && !ent->epVelocity[2])
|
||||
{ //nothing to do if we have no velocity even after gravity.
|
||||
if (ent->touch)
|
||||
{ //call touch if we're in something
|
||||
trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ent->s.number, ent->clipmask);
|
||||
if (tr.startsolid || tr.allsolid)
|
||||
{
|
||||
ent->touch(ent, &g_entities[tr.entityNum], &tr);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//get the projected origin based on velocity.
|
||||
VectorMA(ent->r.currentOrigin, velScaling, ent->epVelocity, projectedOrigin);
|
||||
|
||||
VectorScale(ent->epVelocity, 1.0f-mass, ent->epVelocity); //scale it down based on mass
|
||||
|
||||
VectorCopy(ent->epVelocity, vNorm);
|
||||
vTotal = VectorNormalize(vNorm);
|
||||
|
||||
if (vTotal < 1 && ent->s.groundEntityNum != ENTITYNUM_NONE)
|
||||
{ //we've pretty much stopped moving anyway, just clear it out then.
|
||||
VectorClear(ent->epVelocity);
|
||||
ent->epGravFactor = 0;
|
||||
trap_LinkEntity(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->ghoul2 && g2Bolts)
|
||||
{ //Have we been passed a bolt index array to clip against points on the skeleton?
|
||||
vec3_t tMins, tMaxs;
|
||||
vec3_t trajDif;
|
||||
vec3_t gbmAngles;
|
||||
vec3_t boneOrg;
|
||||
vec3_t projectedBoneOrg;
|
||||
vec3_t collisionRootPos;
|
||||
mdxaBone_t matrix;
|
||||
trace_t bestCollision;
|
||||
qboolean hasFirstCollision = qfalse;
|
||||
int i = 0;
|
||||
|
||||
//Maybe we could use a trap call and get the default radius for the bone specified,
|
||||
//but this will do at least for now.
|
||||
VectorSet(tMins, -3, -3, -3);
|
||||
VectorSet(tMaxs, 3, 3, 3);
|
||||
|
||||
gbmAngles[PITCH] = gbmAngles[ROLL] = 0;
|
||||
gbmAngles[YAW] = ent->s.apos.trBase[YAW];
|
||||
|
||||
//Get the difference relative to the entity origin and projected origin, to add to each bolt position.
|
||||
VectorSubtract(ent->r.currentOrigin, projectedOrigin, trajDif);
|
||||
|
||||
while (i < numG2Bolts)
|
||||
{
|
||||
//Get the position of the actual bolt for this frame
|
||||
trap_G2API_GetBoltMatrix(ent->ghoul2, 0, g2Bolts[i], &matrix, gbmAngles, ent->r.currentOrigin, level.time, NULL, ent->modelScale);
|
||||
BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, boneOrg);
|
||||
|
||||
//Now add the projected positional difference into the result
|
||||
VectorAdd(boneOrg, trajDif, projectedBoneOrg);
|
||||
|
||||
trap_Trace(&tr, boneOrg, tMins, tMaxs, projectedBoneOrg, ent->s.number, ent->clipmask);
|
||||
|
||||
if (tr.fraction != 1.0 || tr.startsolid || tr.allsolid)
|
||||
{ //we've hit something
|
||||
//Store the "deepest" collision we have
|
||||
if (!hasFirstCollision)
|
||||
{ //don't have one yet so just use this one
|
||||
bestCollision = tr;
|
||||
VectorCopy(boneOrg, collisionRootPos);
|
||||
hasFirstCollision = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tr.allsolid && !bestCollision.allsolid)
|
||||
{ //If the whole trace is solid then this one is deeper
|
||||
bestCollision = tr;
|
||||
VectorCopy(boneOrg, collisionRootPos);
|
||||
}
|
||||
else if (tr.startsolid && !bestCollision.startsolid && !bestCollision.allsolid)
|
||||
{ //Next deepest is if it's startsolid
|
||||
bestCollision = tr;
|
||||
VectorCopy(boneOrg, collisionRootPos);
|
||||
}
|
||||
else if (!bestCollision.startsolid && !bestCollision.allsolid &&
|
||||
tr.fraction < bestCollision.fraction)
|
||||
{ //and finally, if neither is startsolid/allsolid, but the new one has a smaller fraction, then it's closer to an impact point so we will use it
|
||||
bestCollision = tr;
|
||||
VectorCopy(boneOrg, collisionRootPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (hasFirstCollision)
|
||||
{ //at least one bolt collided
|
||||
//We'll get the offset between the collided bolt and endpos, then trace there
|
||||
//from the origin so that our desired position becomes that point.
|
||||
VectorSubtract(collisionRootPos, bestCollision.endpos, trajDif);
|
||||
|
||||
VectorAdd(ent->r.currentOrigin, trajDif, projectedOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
//If we didn't collide with any bolts projectedOrigin will still be the original desired
|
||||
//projected position so all is well. If we did then projectedOrigin will be modified
|
||||
//to provide us with a relative position which does not place the bolt in a solid.
|
||||
trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, projectedOrigin, ent->s.number, ent->clipmask);
|
||||
|
||||
if (tr.startsolid || tr.allsolid)
|
||||
{ //can't go anywhere from here
|
||||
#ifdef _DEBUG
|
||||
Com_Printf("ExPhys object in solid (%i)\n", ent->s.number);
|
||||
#endif
|
||||
if (autoKill)
|
||||
{
|
||||
ent->think = G_FreeEntity;
|
||||
ent->nextthink = level.time;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Go ahead and set it to the trace endpoint regardless of what it hit
|
||||
G_SetOrigin(ent, tr.endpos);
|
||||
trap_LinkEntity(ent);
|
||||
|
||||
if (tr.fraction == 1.0f)
|
||||
{ //Nothing was in the way.
|
||||
return;
|
||||
}
|
||||
|
||||
if (bounce)
|
||||
{
|
||||
vTotal *= bounce; //scale it by bounce
|
||||
|
||||
VectorScale(tr.plane.normal, vTotal, vNorm); //scale the trace plane normal by the bounce factor
|
||||
|
||||
if (vNorm[2] > 0)
|
||||
{
|
||||
ent->epGravFactor -= vNorm[2]*(1.0f-mass); //The lighter it is the more gravity will be reduced by bouncing vertically.
|
||||
if (ent->epGravFactor < 0)
|
||||
{
|
||||
ent->epGravFactor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//call touch first so we can check velocity upon impact if we want
|
||||
if (tr.entityNum != ENTITYNUM_NONE && ent->touch)
|
||||
{ //then call the touch function
|
||||
ent->touch(ent, &g_entities[tr.entityNum], &tr);
|
||||
}
|
||||
|
||||
VectorAdd(ent->epVelocity, vNorm, ent->epVelocity); //add it into the existing velocity.
|
||||
}
|
||||
else
|
||||
{ //if no bounce, kill when it hits something.
|
||||
ent->epVelocity[0] = 0;
|
||||
ent->epVelocity[1] = 0;
|
||||
|
||||
if (!gravity)
|
||||
{
|
||||
ent->epVelocity[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user