Add avelocity support to MOVETYPE_PUSH entities, to go with rotated SOLID_BSP support (kinda pointless without this commit too tbh).

This commit is contained in:
Shpoike 2020-04-07 00:58:07 +01:00
parent 9d15653e46
commit 9278c740db

View file

@ -447,6 +447,210 @@ trace_t SV_PushEntity (edict_t *ent, vec3_t push)
SV_PushMove
============
*/
static qboolean SV_PushMoveAngles (edict_t *pusher, float movetime)
{
int i, e;
edict_t *check, *block;
vec3_t mins, maxs;
//float oldsolid;
vec3_t org, org2, move2, forward, right, up;
vec3_t move, amove;
struct {
edict_t *ent;
vec3_t origin;
vec3_t angles;
} *pushed, *pushed_p, *p;
for (i=0 ; i<3 ; i++)
{
move[i] = pusher->v.velocity[i] * movetime;
amove[i] = pusher->v.avelocity[i] * movetime;
mins[i] = pusher->v.absmin[i] + move[i];
maxs[i] = pusher->v.absmax[i] + move[i];
}
//using johnfitz's dynamic alloc strategy, consistent with SV_PushMove
pushed_p = pushed = Hunk_Alloc (qcvm->num_edicts*sizeof(*pushed));
// find the bounding box
for (i=0 ; i<3 ; i++)
{
mins[i] = pusher->v.absmin[i] + move[i];
maxs[i] = pusher->v.absmax[i] + move[i];
}
// we need this for pushing things later
VectorSubtract(vec3_origin, amove, org);
AngleVectors (org, forward, right, up);
// save the pusher's original position
pushed_p->ent = pusher;
VectorCopy (pusher->v.origin, pushed_p->origin);
VectorCopy (pusher->v.angles, pushed_p->angles);
pushed_p++;
// move the pusher to it's final position
VectorAdd (pusher->v.origin, move, pusher->v.origin);
VectorAdd (pusher->v.angles, amove, pusher->v.angles);
SV_LinkEdict (pusher, false);
// see if any solid entities are inside the final position
check = NEXT_EDICT(qcvm->edicts);
for (e = 1; e < qcvm->num_edicts; e++, check = NEXT_EDICT(check))
{
if (check->free)
continue;
if (check->v.movetype == MOVETYPE_PUSH
|| check->v.movetype == MOVETYPE_NONE
|| check->v.movetype == MOVETYPE_NOCLIP
|| check->v.movetype == MOVETYPE_ANGLENOCLIP)
continue;
/*
oldsolid = pusher->v->solid;
pusher->v->solid = SOLID_NOT;
block = World_TestEntityPosition (w, check);
pusher->v->solid = oldsolid;
if (block)
continue;
*/
// if the entity is standing on the pusher, it will definitely be moved
if ( ! ( ((int)check->v.flags & FL_ONGROUND)
&& PROG_TO_EDICT(check->v.groundentity) == pusher) )
{
// see if the ent needs to be tested
if ( check->v.absmin[0] >= maxs[0]
|| check->v.absmin[1] >= maxs[1]
|| check->v.absmin[2] >= maxs[2]
|| check->v.absmax[0] <= mins[0]
|| check->v.absmax[1] <= mins[1]
|| check->v.absmax[2] <= mins[2] )
continue;
// see if the ent's bbox is inside the pusher's final position
if (!SV_TestEntityPosition (check))
continue;
}
if ((pusher->v.movetype == MOVETYPE_PUSH) || (PROG_TO_EDICT(check->v.groundentity) == pusher))
{
// move this entity
pushed_p->ent = check;
VectorCopy (check->v.origin, pushed_p->origin);
VectorCopy (check->v.angles, pushed_p->angles);
pushed_p++;
// try moving the contacted entity
VectorAdd (check->v.origin, move, check->v.origin);
VectorAdd (check->v.angles, amove, check->v.angles);
// figure movement due to the pusher's amove
VectorSubtract (check->v.origin, pusher->v.origin, org);
org2[0] = DotProduct (org, forward);
org2[1] = -DotProduct (org, right);
org2[2] = DotProduct (org, up);
VectorSubtract (org2, org, move2);
VectorAdd (check->v.origin, move2, check->v.origin);
if (check->v.movetype != MOVETYPE_WALK)
check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
// may have pushed them off an edge
if (PROG_TO_EDICT(check->v.groundentity) != pusher)
check->v.groundentity = 0;
block = SV_TestEntityPosition (check);
if (!block)
{ // pushed ok
SV_LinkEdict (check, false);
// impact?
continue;
}
// if it is ok to leave in the old position, do it
// this is only relevent for riding entities, not pushed
// FIXME: this doesn't acount for rotation
VectorCopy (pushed_p[-1].origin, check->v.origin);
block = SV_TestEntityPosition (check);
if (!block)
{
pushed_p--;
continue;
}
//okay, that didn't work, try pushing the against stuff
SV_PushEntity(check, move);
block = SV_TestEntityPosition (check);
if (!block)
continue;
VectorCopy(check->v.origin, move);
for (i = 0; i < 8 && block; i++)
{
//precision errors can strike when you least expect it. lets try and reduce them.
check->v.origin[0] = move[0] + ((i&1)?-1:1)/8.0;
check->v.origin[1] = move[1] + ((i&2)?-1:1)/8.0;
check->v.origin[2] = move[2] + ((i&4)?-1:1)/8.0;
block = SV_TestEntityPosition (check);
}
if (!block)
{
SV_LinkEdict (check, false);
continue;
}
}
// if it is sitting on top. Do not block.
if (check->v.mins[0] == check->v.maxs[0])
{
SV_LinkEdict (check, false);
continue;
}
//some pushers are contents brushes, and are not solid. water cannot crush. the player just enters the water.
//but, the player will be moved along with the water if possible.
if (pusher->v.skin < 0)
continue;
if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
{ // corpse
check->v.mins[0] = check->v.mins[1] = 0;
VectorCopy (check->v.mins, check->v.maxs);
SV_LinkEdict (check, false);
continue;
}
// Con_Printf("Pusher hit %s\n", PR_GetString(w->progs, check->v->classname));
if (pusher->v.blocked)
{
pr_global_struct->self = EDICT_TO_PROG(pusher);
pr_global_struct->other = EDICT_TO_PROG(check);
PR_ExecuteProgram (pusher->v.blocked);
}
// move back any entities we already moved
// go backwards, so if the same entity was pushed
// twice, it goes back to the original position
for (p=pushed_p-1 ; p>=pushed ; p--)
{
VectorCopy (p->origin, p->ent->v.origin);
VectorCopy (p->angles, p->ent->v.angles);
SV_LinkEdict (p->ent, false);
}
return false;
}
//FIXME: is there a better way to handle this?
// see if anything we moved has touched a trigger
for (p=pushed_p-1 ; p>=pushed ; p--)
SV_LinkEdict (p->ent, true);
return true;
}
void SV_PushMove (edict_t *pusher, float movetime)
{
int i, e;
@ -459,6 +663,15 @@ void SV_PushMove (edict_t *pusher, float movetime)
int mark; //johnfitz
float solid_backup;
if ((pusher->v.avelocity[0] || pusher->v.avelocity[1] || pusher->v.avelocity[2]) && pr_checkextension.value)
{ //spike -- added this block for proper rotations
mark = Hunk_LowMark ();
if (SV_PushMoveAngles (pusher, movetime))
pusher->v.ltime += movetime;
Hunk_FreeToLowMark (mark);
return;
}
if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
{
pusher->v.ltime += movetime;